题意
有一排(n)个格子,(i)操作会使(i)和(i+1)都变黑。
一个操作序列的得分为染黑所有格子时所用的步数
问所有排列的得分和。
(nle 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
",ans);
}
后记
好神仙啊