计数DP(Zero Escape,HDU 5389)

来源:互联网 发布:四川省教师网络培训 编辑:程序博客网 时间:2024/05/20 16:13

题目连接:https://vjudge.net/problem/HDU-5389

利用数根的特性,数值在1~9的小范围,结果在1~9的小范围,数之间顺序无关,组合数公式等进行计数DP。

关于数根的特性:

http://blog.csdn.net/ray0354315/article/details/53991199


代码

#include<stdio.h>#include<string.h>#include<utility>using namespace std;const int mod = 258280327;const int maxn = 100010;typedef pair<int,int> pii;int n,A,B;int cnt[12];int dp[12][12][12];int inv[maxn];int tp;void read(){    tp=0;    scanf("%d %d %d",&n,&A,&B);    memset(cnt,0,sizeof(cnt));    int x;    for(int i=1;i<=n;i++)    {        scanf("%d",&x);        tp=(tp+x)%9;        ++cnt[x];    }    memset(dp,0,sizeof(dp));    dp[0][0][0]=1;}void solve(){    read();    for(int cur=1;cur<=9;cur++)    {        int C = 1;        for(int k=0;k<=cnt[cur];k++)        {            for(int i=0;i<9;i++)                for(int j=0;j<9;j++)                    dp[cur][(i+1ll*k*cur)%9][(j+1ll*(cnt[cur]-k)*cur)%9]=(dp[cur][(i+1ll*k*cur)%9][(j+1ll*(cnt[cur]-k)*cur)%9]+1ll*dp[cur-1][i][j]*C%mod)%mod;            C=1ll*C*(cnt[cur]-k)%mod*inv[k+1]%mod;        }    }    int ans=dp[9][A%9][B%9];    pii p = make_pair(A%9,B%9);    if(A%9==tp&&p!=make_pair(tp,0))        ans=(ans+1)%mod;    if(B%9==tp&&p!=make_pair(0,tp))        ans=(ans+1)%mod;    printf("%d\n",ans);}int mp(int x,int n){    int ret=1;    while(n)    {        if(n&1) ret=1ll*ret*x%mod;        x=1ll*x*x%mod;        n>>=1;    }    return ret;}void init(){    for(int i=1;i<maxn;i++) inv[i]=mp(i,mod-2);}int main(){    init();    int T;    scanf("%d",&T);    while(T--) solve();    return 0;}