計數DP(Zero Escape,HDU 5389)

題目連接: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;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章