Codeforces Global Round 24 D
阿新 • • 發佈:2022-11-29
D. Doremy's Pegging Game
題目連結
挺難的一道計數
計數問題最重要的是考慮如果劃分集合 然後不重不漏地計算出來
我們考慮列舉每一個序列的結束點
就是有n個 然後這n個顯然是等價的 所以我們最後n即可
然後我們可以發現我們結束狀態一定是“一邊”點 就是最遠的點距離不超過n/2
這樣我們就可以列舉“邊”的起始 然後O(1)計算即可
我們邊中間的可以在可以不在
設邊除了起始兩個點還有x個點
然後可以預處理邊內點選i=0,1,2,3,....x個要刪掉時的也就是Cxi再一共有多少點刪掉的全排列
我們預處理出這個sum[x]
最後再列舉邊的時候判斷一下合法性
再最後判斷一下n是偶數是 可以有一種特殊的對著的兩個點的特殊情況即可
int a[N],b[N],p; int qmi(int a,int k,int p){ int res=1; while(k){ if(k&1)res=(res*a)%p; k>>=1; a=a*a%p; } return res; } int C(int x,int y){ if(x<0||y<0||x<y)return 0; return a[x]*b[y]%p*b[x-y]%p; } vector<int>A(N); void init(){ a[0]=b[0]=1; for(int i=1;i<=1e5;i++){ a[i]=(a[i-1]*i)%p; b[i]=b[i-1]*qmi(i,p-2,p)%p; } } void solve(){ int n;cin>>n>>p; init(); A[0]=1; for(int i=1;i<=n;i++)A[i]=A[i-1]*i%p; vector<int>sum(n+10); for(int x=0;x<=n-3;x++){ for(int j=0;j<=x;j++){ (sum[x]+=C(x,j)*A[n-x-3+j]%p)%=p; } } int ans=0; for(int i=2;i<=n/2+1;i++){ for(int j=i+1;j<=n;j++){ int x=j-i; if(x<up(n,2)&&j>up(n,2)){ (ans+=sum[x-1])%=p; } } } if(n%2==0){ (ans+=A[n-2])%=p; } cout<<ans*n%p<<endl; }