1. 程式人生 > 其它 >Codeforces Global Round 24 D

Codeforces Global Round 24 D

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;
}