【JZOJ5330】【NOIP2017提高A組模擬8.22】密碼【51nod1569】二項式係數的個數

Description

這裏寫圖片描述

Data Constraint

這裏寫圖片描述

Solution

首先有個庫默爾定理:設m,n爲正整數,p爲素數,則Cmm+n 含p的冪次等於m+n在p進制下的進位次數。
於是我們就很好辦了,顯然當k大於n在p進制下的位數答案爲0。我們只要滿足(l-s)+s的進位次數大於等於k即可。我們將n轉化爲p進制下。設f[i][j][k][0..1][0..1]位當前dp到p進制第i位,進位次數爲j,下一位是否僅爲進位,前i位是否與N在p進制下相同的方案。轉移有點多。

Code

#include<iostream>
#include<cmath>
#include<cstring>
#include<cstdio>
#include<algorithm>
#define ll long long
using namespace std;
const ll maxn=4e3+5,mo=1e9+7;
int f[maxn][maxn][2][2],a[maxn],b[maxn],c[maxn];
ll n,p,q,i,t,j,k,l,x,y,z,ln,ln1,ans;
char s[maxn];
void make(){
    ll i,j,k,x=0;
    for (i=1;i<=c[0];i++){
        c[i]+=x*10;
        x=c[i]%p;c[i]/=p;
    }
    j=1;b[b[0]]=x;
    while (j<=c[0] && !c[j]) j++;
    if (j>c[0]) c[0]=0;
    else{
        for (i=j;i<=c[0];i++)
            c[i-j+1]=c[i];
        c[0]-=j-1;
    }
}
int main(){
    freopen("password.in","r",stdin);freopen("password.out","w",stdout);
    scanf("%s%d%d",s+1,&p,&q);n=strlen(s+1);
    for(i=1;i<=n;i++)c[i]=s[i]-48;c[c[0]]=n;
    while (c[0])
        b[0]++,make();
    if (b[0]<q){
        printf("0\n");return 0;
    }
    f[b[0]+1][0][0][1]=1;ln=p*(p+1)/2%mo;ln1=p*(p-1)/2%mo;
    for (i=b[0]+1;i>1;i--){
        x=b[i-1];
        k=(x+1)*x/2%mo;l=x*(x-1)/2%mo;t=((x-1)*x/2+x*(p-x))%mo;y=(x*(x-1)/2+x*(p-x+1))%mo;
        for (j=0;j<=b[0]-i+1;j++){
            if (f[i][j][0][0]){
                f[i-1][j][0][0]=(f[i-1][j][0][0]+f[i][j][0][0]*ln%mo)%mo;
                f[i-1][j+1][1][0]=(f[i-1][j+1][1][0]+f[i][j][0][0]*ln1%mo)%mo;
            }
            if (f[i][j][1][0]){
                f[i-1][j][0][0]=(f[i-1][j][0][0]+f[i][j][1][0]*ln1%mo)%mo;
                f[i-1][j+1][1][0]=(f[i-1][j+1][1][0]+f[i][j][1][0]*ln%mo)%mo;
            }
            if (f[i][j][0][1]){
                f[i-1][j][0][0]=(f[i-1][j][0][0]+f[i][j][0][1]*k%mo)%mo;
                f[i-1][j][0][1]=(f[i-1][j][0][1]+f[i][j][0][1]*(x+1)%mo)%mo;
                f[i-1][j+1][1][0]=(f[i-1][j+1][1][0]+f[i][j][0][1]*l%mo)%mo;
                f[i-1][j+1][1][1]=(f[i-1][j+1][1][1]+f[i][j][0][1]*x%mo)%mo;
            }
            if (f[i][j][1][1]){
                f[i-1][j][0][0]=(f[i-1][j][0][0]+f[i][j][1][1]*t%mo)%mo;
                f[i-1][j+1][1][0]=(f[i-1][j+1][1][0]+f[i][j][1][1]*y%mo)%mo;
                f[i-1][j][0][1]=(f[i-1][j][0][1]+f[i][j][1][1]*(p-x-1)%mo)%mo;
                f[i-1][j+1][1][1]=(f[i-1][j+1][1][1]+f[i][j][1][1]*(p-x)%mo)%mo;
            }
        }
    }
    ans=0;
    for (i=q;i<=b[0];i++)
        ans=(ans+(f[1][i][0][0]+f[1][i][0][1])%mo)%mo;
    printf("%lld\n",ans);
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章