AGC023C Painting Machines

题意

有一排\(n\)个格子,\(i\)操作会使\(i\)\(i+1\)都变黑。
一个操作序列的得分为染黑所有格子时所用的步数
问所有排列的得分和。
\(n\le 10^6\)
传送门

思路

有一个很直观的感觉:要枚举步数。然后问题就是如何在\(O(1)\)时间内求出排列数。
考虑\(1\)\(n-1\)是必须染的,剩下的操作只要相邻两个相差不超过\(2\)就好了。那么可以发现要么是一个挨着一个,要么是一个空一格,转化成求有多少种安排空格的方法。
\(k\)个操作,取掉头尾\(k-2\)个,总共\(k-1\)个间隔,要放入\((n-k)-1\)个空格,所以可行的组合数使\(C(k-1,n-k-1)\)然后再乘上\(k!\)以及剩下的\((n-1-k)!\),但发现有可能会有\(k\)步之前就完成的,只要减去\(k-1\)时的答案就好了

#include <bits/stdc++.h>
const int N=1000005,mu=1000000007;
int inv[N],p[N],n,ans,last; 
int ksm(int x,int y){
	int ans=1;
	for (;y;y>>=1,x=x*1ll*x%mu)
		if (y&1) ans=1ll*ans*x%mu;
	return ans;
}
int C(int x,int y){
	return 1ll*p[x]*inv[y]%mu*inv[x-y]%mu;
}
int main(){
	scanf("%d",&n);
	p[0]=1;
	for (int i=1;i<=n;i++) p[i]=1ll*i*p[i-1]%mu;
	inv[n]=ksm(p[n],mu-2);
	for (int i=n-1;i>=0;i--) inv[i]=inv[i+1]*1ll*(i+1)%mu;
	for (int i=(n+1)/2;i<=n-1;i++){
		int x=C(i-1,n-i-1)*1ll*p[i]%mu*p[n-i-1]%mu;
		ans=(ans+i*1ll*(x-last+mu)%mu)%mu;
		last=x;
	}
	printf("%d\n",ans);
}

后记

好神仙啊

posted @ 2019-11-14 19:37  flyfeather  阅读(164)  评论(0编辑  收藏  举报