Problem Description
As an exciting puzzle game for kids and girlfriends, the Matches Puzzle Game asks the player to find the number of possible equations 
In these equations,  )
.

 

Input
The input contains several test cases. The first line of the input is a single integer ).

 

Output
For each test case, you should output the answer modulo m.

 

Sample Input
4 12 1000000007 17 1000000007 20 1000000007 147 1000000007

 

Sample Output
Case #1: 1 Case #2: 5 Case #3: 38 Case #4: 815630825

 

Source
 
 
【题意】
  有n根火柴(n<=500),要刚好用完,摆出一个减式A-B=C(A>0,B>0,C>0)求有多少种方案
 
【分析】
  这题很好想,但是就看个人DP能力了,我一开始打的DP就TLE,真是太年轻!
  之前做的几题数位DP都是数字限制,即数值固定一个区间,而现在这题可不管你那个数有多大,只要火柴够用就好了。
  所以之前的题我是记录位数,标记前导0的,再加个越限标记flag。
  搞到我这题一开始就也记录位数了,然记录位数并无卵用!!还会TLE啊ORZ,
  我一开始想法,先减掉3根火柴,减法变加法(加法好打一些),f[i][j][k]表示i位,j根火柴,k表示状态(即两个加数分别是否还处于前导0中),然后记忆化搜索
  位数不超过n/4的,所以时间大概是150*500*4*10*10*2,代码也放一下,正确性还是保证的:
  
 1 #include<cstdio>
 2 #include<cstdlib>
 3 #include<cstring>
 4 #include<iostream>
 5 #include<algorithm>
 6 #include<queue>
 7 #include<cmath>
 8 using namespace std;
 9 #define LL long long
10 
11 int f[150][510][4][2];//weishu huocai zero shifoujinwei
12 // 0 00 1 0x 2 x0 3 xx
13 int us[10]={6,2,5,5,4,5,6,3,7,6};
14 int m,sum;
15 
16 int ffind(int n,int k,int zero,int step)
17 {
18     sum++;
19     if(k<3) return 0;
20     if(n==0) return (k==3&&step==0);
21     if(f[n][k][zero][step]!=-1) return f[n][k][zero][step]; 
22     LL ans=0;
23     for(int a=0;a<10;a++)
24       for(int b=0;b<10;b++)
25       {
26           for(int l=0;l<2;l++) //xia yi bu shi fou jin wei
27           {
28                 if(n==1&&a==0&&zero<=1) continue;
29                 if(n==1&&b==0&&zero!=1&&zero!=3) continue;
30                   if(step&&(a+b+l<10)) continue;
31                  if(!step&&(a+b+l>=10)) continue;
32                  int now=0;
33                  if(a!=0||zero==2||zero==3) now+=us[a];
34                  if(b!=0||zero==1||zero==3) now+=us[b];
35                  if(a!=0||b!=0||l!=0||zero!=0) now+=us[(a+b+l)%10];
36                  if(now>k) continue;
37                  
38                  int nz;
39                  if(a==0&&b==0&&zero==0) nz=0;
40                  else if(a==0&&zero!=2&&zero!=3) nz=1;
41                  else if(b==0&&zero!=1&&zero!=3) nz=2;
42                  else nz=3;
43                  ans=(ans+ffind(n-1,k-now,nz,l) )%m;
44              }
45          }
46     f[n][k][zero][step]=(int)ans;
47     return (int)ans;
48 }
49 
50 int main()
51 {
52     int T,kase=0;
53     scanf("%d",&T);
54     while(T--)
55     {
56         sum=0;
57         int n;
58         scanf("%d%d",&n,&m);
59         memset(f,-1,sizeof(f));
60         printf("Case #%d: %d\n",++kase,ffind(n/4,n,0,0));
61     }
62     return 0;
63 }
TLE的代码

 

  其实与位数无关,但是不及记录位数就要从低位开始填数了,不然无法表示,会重复。

    f[j][k]表示j根火柴,k状态,状态表示当前两个加数分别是否结束了,结束了只能填0,并且不花费火柴。

 

AC代码如下:

 1 #include<cstdio>
 2 #include<cstdlib>
 3 #include<cstring>
 4 #include<iostream>
 5 #include<algorithm>
 6 #include<queue>
 7 #include<cmath>
 8 using namespace std;
 9 #define LL long long
10 
11 int f[510][4][2];//weishu huocai zero shifoujinwei
12 // 0 00 1 0x 2 x0 3 xx
13 int us[10]={6,2,5,5,4,5,6,3,7,6};
14 int m;
15 
16 int ffind(int k,int zero,int step)
17 {
18     if(k<3) return 0;
19     if(zero==0)
20     {
21         if(step==1) k-=2;
22         return k==3;
23     }
24     if(f[k][zero][step]!=-1) return f[k][zero][step]; 
25     LL ans=0;
26     for(int a=0;a<10;a++)
27     {
28         for(int b=0;b<10;b++)
29         {
30                  int now=0;
31                  if(zero==2||zero==3) now+=us[a];
32                  if(zero==1||zero==3) now+=us[b];
33                  now+=us[(a+b+step)%10];
34                  if(now>k) continue;
35                  
36                  ans=(ans+ffind(k-now,zero,a+b+step>=10) )%m;
37                  if(a!=0&&zero!=0&&zero!=1) ans=(ans+ffind(k-now,zero==3?1:0,a+b+step>=10) )%m;
38                  if(b!=0&&zero!=0&&zero!=2) ans=(ans+ffind(k-now,zero==3?2:0,a+b+step>=10) )%m;
39                  if(a!=0&&b!=0&&zero==3) ans=(ans+ffind(k-now,0,a+b+step>=10) )%m;
40                  
41              if(zero==0||zero==2) break;
42          }
43          if(zero==0||zero==1) break;
44     }
45       
46     f[k][zero][step]=(int)ans;
47     return (int)ans;
48 }
49 
50 int main()
51 {
52     int T,kase=0;
53     scanf("%d",&T);
54     while(T--)
55     {
56         int n;
57         scanf("%d%d",&n,&m);
58         memset(f,-1,sizeof(f));
59         printf("Case #%d: %d\n",++kase,ffind(n,3,0));
60     }
61     return 0;
62 }
[HDU 5456]

相关文章: