HDU5456 Matches Puzzle Game[數位DP]


題意:

給T組數據,每組數組給一個n和m。n代表有n根小棍,問用這些小棍去組成一個A-B=C的等式有多少種方法,結果取模m。


題解:

先把題目所給的數字的擺法需要的個數,用數組存起來。

注意這個題並沒有一個上界來讓我們進行保存dfs過程中的值,所以只能進行每組數據的時候,重新將dp重置爲-1,不然答案並不對。

根據等式,我們可以直接轉換成A=B+C的形式,那麼我們我們只需要枚舉每一位的B和C進行加法運算,如果需要進位就標記一下。

這樣我們一共有8種狀態,換成二進制的形式

000 代表三個都沒枚舉完畢

001 代表C已經是確定的了

010 代表B已經是確定的了

011 代表BC都已經是確定的

100 代表A是確定的了(但是這種狀態必須保證BC已存在,所以在計算過程中並不會單獨出現)

101 同上 同時C已確定,但是這種狀態不存在

110 同上 同時B已確定,但是這種狀態不存在

111 代表三個都枚舉出來了

dfs的時候,需要同時枚舉出當前位的B和C,所以有個二重循環,用當前位BC的和計算出A的當前位,並標記是否有進位,如果B已存在,那麼B只能出現數字0,如果C已存在,那麼也只能出現數字0。

A成功枚舉出來僅噹噹前枚舉不出現進位,並且sum(當前BCA枚舉出來的消耗)+3=剩餘值,A纔可成功,因爲+3是指減號-號跟等號=的三根小棍。

狀態轉移的話,dp[i][j][k] 第一維表示剩餘可用的小棍數,第二維表示是否需要進位,第三維表示當前枚舉ABC的枚舉狀態,即上述。



#pragma comment(linker, "/STACK:102400000,102400000")
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<string>
#include<algorithm>
#include<queue>
#include<stack>
#include<set>
#include<map>
#include<vector>
using namespace std;
typedef long long ll;
const int N=1e3;
int n;
int use[]={6,2,5,5,4,5,6,3,7,6};
ll m;
ll dp[N][2][1<<3];
//001 c存在 010 b存在 100 a存在
ll dfs(int left,int up,int state)
{
    if (dp[left][up][state]!=-1)
        return dp[left][up][state];
    if (left<=0)
        return (!left && !up && state==7);
    ll cnt=0;
    for (int i=0 ; i<10 ; ++i)
    {
        if (state&2 && i)
                break;
        for (int j=0 ; j<10 ; ++j)
        {
            int b=i,c=j,a=(i+j+up)%10;
            if ((state&1 && c) || (state&2 && b))
                break;
            int sum=(state&1?0:use[c])+(state&2?0:use[b])+use[a];
            if (sum>left)
                continue;
            bool visit[8]={0};
            bool need=(i+j+up)>=10;
            for (int k=0 ; k<8 ; ++k)
            {
                bool flag=0;
                int t=0;
                if (k&1 && c)
                    t|=1;
                if (k&2 && b)
                    t|=2;
                if (k&4 && a && !need && left==sum+3)
                {
                    t|=4;
                    flag=1;
                }
                if (!visit[t])
                {
                    if (flag)
                        cnt=(cnt+dfs(left-sum-3,need,state|t))%m;
                    else
                        cnt=(cnt+dfs(left-sum,need,state|t))%m;
                    visit[t]=1;
                }
            }
        }
    }
    return dp[left][up][state]=cnt;
}
int main()
{
	int T;
	scanf("%d",&T);
	for (int test=1 ; test<=T ; ++test)
    {
        scanf("%d%lld",&n,&m);
        memset(dp,-1,sizeof(dp));
        printf("Case #%d: %lld\n",test,dfs(n,0,0));
    }
	return 0;
}




發佈了51 篇原創文章 · 獲贊 15 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章