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

  

posted @ 2017-03-19 20:46  SfailSth  阅读(229)  评论(0编辑  收藏  举报