codeforces 582D

来源:互联网 发布:matlab中粒子群算法 编辑:程序博客网 时间:2024/06/05 00:16

emmmmmmmmmmmmmm
这题模拟赛的时候做过
当时back的时候推柿子推得很痛苦
现在再做还是不会….不过推柿子变得熟练了很多…

题解:
因为组合数可以写成阶乘的形式Cmn=n!m!(nm)!
又因为p是质数,组合数能否被pk整除取决于他含多少个p作为因子
所以我们不妨先考虑阶乘n!含多少个p
假设n!含有kp作为因子,有k=i=1npi (易证)
那么Cmn含有的p的个数就是i=1npimpinmpi
写在p进制下,容易发现对于每个i,那个计算式只会是0或者1,且取决于m和n-m加起来在第i位是否产生了进位
所以问n,m<=A时有多少个Cmnpk整除,就是问有多少对数x,y,满足x+y<=A且在p进制下产生了至少k次进位

我们将A转成p进制,做数位dp
dp[i][x][0/1][0/1]表示dp到第i位,已经产生了x次进位,前面是否顶格,下一位是否会进位的方案数

code:

#include<set>#include<map>#include<deque>#include<queue>#include<stack>#include<cmath>#include<ctime>#include<bitset>#include<string>#include<vector>#include<cstdio>#include<cstdlib>#include<cstring>#include<climits>#include<complex>#include<iostream>#include<algorithm>#define ll long longusing namespace std;const int maxn = 3500;const ll Mod = 1e9+7;int n;ll p,m;char str[maxn];int t[maxn],t2[maxn],L,len,A[maxn],tp;ll f[2][maxn][2][2];ll cal(const ll x){ return x*(x+1)/2%Mod; }ll dp(){    int now=0; f[now][0][1][0]=1;    for(int j=tp;j>=1;j--)    {        now=!now;        ll k=A[j];        for(int i=0;i<tp;i++)        {            ll tmp=f[!now][i][0][0]%Mod; f[!now][i][0][0]=0;            if(tmp)            {                f[now][i+1][0][1]+=cal(p-1)*tmp%Mod;                f[now][i][0][0]+=cal(p)*tmp%Mod;            }            tmp=f[!now][i][0][1]%Mod; f[!now][i][0][1]=0;            if(tmp)            {                f[now][i+1][0][1]+=cal(p)*tmp%Mod;                f[now][i][0][0]+=cal(p-1)*tmp%Mod;            }            tmp=f[!now][i][1][0]%Mod; f[!now][i][1][0]=0;            if(tmp)            {                f[now][i][1][0]+=(k+1)*tmp%Mod;                f[now][i+1][1][1]+=k*tmp%Mod;                f[now][i][0][0]+=cal(k)*tmp%Mod;                f[now][i+1][0][1]+=cal(k-1)*tmp%Mod;            }            tmp=f[!now][i][1][1]%Mod; f[!now][i][1][1]=0;            if(tmp)            {                f[now][i][1][0]+=(p-k-1)*tmp%Mod;                f[now][i+1][1][1]+=(p-k)*tmp%Mod;                f[now][i][0][0]+=(cal(p-1)-cal(p-k-1))*tmp%Mod;                f[now][i+1][0][1]+=(cal(p)-cal(p-k))*tmp%Mod;            }        }    }    ll re=0;    for(int x=m;x<tp;x++)    {        for(int i=0;i<2;i++)            (re+=f[now][x][i][0]%Mod)%=Mod;    }    if(re<0) re+=Mod;    return re;}ll divide(){    ll now=0;    for(int i=L;i<=len;i++)    {        now=now*10+t[i];        t2[i]=now/p; now%=p;    }    for(int i=1;i<=len;i++) t[i]=t2[i],t2[i]=0;    while(!t[L]&&L<=len) L++;    return now;}int main(){    scanf("%I64d%I64d",&p,&m);    scanf("%s",str); len=strlen(str);    for(int i=1;i<=len;i++) t[i]=str[i-1]-'0';    tp=0; while(L<=len) A[++tp]=divide();    if(tp<=m) puts("0");    else printf("%I64d\n",dp());    return 0;}
原创粉丝点击