HDU5456 Matches Puzzle Game[数位DP]

来源:互联网 发布:如何查询域名的有效期 编辑:程序博客网 时间:2024/05/21 10:22

E - Matches Puzzle Game

 HDU - 5456 






题意:

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