BZOJ 1974 [Sdoi2010]auction 代码拍卖会 ——动态规划
把每一位上不递减的数拆成1+11+11111+11111+.....
然后就可以把巨大的N从复杂度中消掉,因为随着长度的增加1...111%p出现了循环节。
然后就是从n个数中选出几个使他们结果为0(mod p)
然后就可以DP了,因为不能有前导零,需要最后再加上以一个数。
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; #define F(i,j,k) for (ll i=j;i<=k;++i) #define D(i,j,k) for (ll i=j;i>=k;--i) #define ll long long #define mod 999911659LL ll x,n,p,cnt[505],tot,sz,now=0,pre=1,add,flag[505],pp=0; ll dp[2][510][10],fac[20],fac_inv[20]; ll C(ll n,ll m) { ll ret=fac_inv[m]; for (n%=mod;m--;ret=1LL*ret*n%mod,n--); return ret; } ll qpow(ll a,ll b) { ll ret=1; while (b) { if (b&1) (ret*=a)%=mod; (a*=a)%=mod; b>>=1; } return ret; } int main() { scanf("%lld%lld",&n,&p); add=x=1;tot=0; x%=p; for (tot=0;tot<n;++tot) { if (cnt[x]) break; flag[x]=++pp; cnt[x]++; add=x; x=(x*10+1)%p; } sz=(n-tot)/(pp+1-flag[x]); tot=(n-tot)%(pp+1-flag[x]); F(i,0,p-1) if (flag[i]>=flag[x]&&flag[i]<=pp)cnt[i]=cnt[i]*(sz+1); for (ll i=0;i<tot;++i) cnt[x]++,add=x,x=(x*10+1)%p; F(i,0,p-1) cnt[i]%=mod; fac[0]=1;F(i,1,15) fac[i]=(fac[i-1]*i)%mod; add=(p-add)%p; F(i,0,15) fac_inv[i]=qpow(fac[i],mod-2); now=1; pre=0; memset(dp[now],0,sizeof dp[now]); dp[now][0][0]=1; if (cnt[0]) F(i,1,8) dp[now][0][i]=C(cnt[0]+i-1,i); F(i,1,p-1) if (cnt[i]){ now^=1;pre^=1; memset(dp[now],0,sizeof dp[now]); F(j,0,p-1) F(k,0,8) if (dp[pre][j][k]) F(l,0,9LL-k-1) dp[now][(j+i*l)%p][k+l]=(dp[now][(j+i*l)%p][k+l]+1LL*dp[pre][j][k]*C(cnt[i]+l-1,l))%mod; } ll ans=0; F(i,0,8) (ans+=dp[now][add][i])%=mod; printf("%lld\n",ans); }