[CodeForces 1284C]New Year and Permutation(DP)

在这里插入图片描述题意
若一个1 ~ n的排列中存在一个区间 [ L , R ] [L,R] [L,R]使得这个区间内元素的最大值与最小值之差为 R − L R-L RL,则称其为一个片段,显然所有长度为1的区间均为一个片段。现在给定n与一个素数m,求1 ~ n的全排列中所有片段数之和对m取模的结果。
1 ≤ n ≤ 250000 , 1 0 8 ≤ m ≤ 1 0 9 1≤n≤250000, 10^8≤m≤10^9 1n250000,108m109
思路
这题是个DP,乍一看没有什么想法简单暴力显然行不通,求出每个排列然后依次统计必然是TLE的。
所以我们换一个思路,求出每种长度的片段数,再计算一下对于每种长度的片段,它在所有 1 1 1 ~ n n n的排列中有多少种放法,把它们乘起来求和就搞定了。
具体来说,对于 1 1 1 ~ n n n的排列,长度为 i i i片段,假设这个片段包含的元素为 X X X ~ X + i − 1 X+i-1 X+i1

  • 这个片段自身有 i ! i! i种排列方式
  • 剩下有 n − i n-i ni个数,则这个片段可以放置在 ( n − i + 1 ) (n-i+1) ni+1个不同的位置(在它前面分别有0,1,…, n − i n-i ni个数)
  • 剩下的 n − i n-i ni个数有 ( n − i ) ! (n-i)! (ni)!种排列方式
  • L的取值有 1 1 1 ~ ( n − i + 1 ) (n-i+1) (ni+1) ( n − i + 1 ) (n-i+1) (ni+1)
    所以对于长度为 i i i片段,总共有 i ! ∗ ( n − i ) ! ∗ ( n − i + 1 ) ∗ ( n − i + 1 ) i!*(n-i)!*(n-i+1)*(n-i+1) inini+1ni+1种放置方式,枚举考虑 i = 1 , 2...... , n i=1,2......,n i=1,2......,n的情况求和即可。

然后我因为忘记取模wa了3发
保险起见,最好在每次乘积之后都进行一次取模运算。

AC代码

#include<stdio.h>
long long m,n;
long long mu[250005];
long long ans;
int main()
{
	scanf("%I64d%I64d",&n,&m);
	mu[0]=1;
	for(int i=1;i<=250000;i++)
	{mu[i]=mu[i-1]*(long long)i;mu[i]%=m;};
	for(int i=1;i<=n;i++)
	{
		ans+=((((mu[i]*mu[n-i]%m)*(n-((long long)i-1))%m)*(n-((long long)i-1)))%m);
		ans%=m;
	}
	printf("%I64d",ans);
	return 0;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值