• 【HDU 5456】 Matches Puzzle Game (数位DP)


    Matches Puzzle Game



    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 AB=C with exactly n (5n500) matches (or sticks).

    In these equations, A,B and C are positive integers. The equality sign needs two matches and the sign of subtraction needs just one. Leading zeros are not allowed.

    Please answer the number, modulo a given integer m (3m2×109).
    Input
    The input contains several test cases. The first line of the input is a single integer t which is the number of test cases. Then t (1t30) test cases follow.

    Each test case contains one line with two integers n (5n500) and m (3m2×109).
    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
    ",++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
    ",++kase,ffind(n,3,0));
    60     }
    61     return 0;
    62 }
    [HDU 5456]

    所以如果跟位数无关,最好思想回到原始的位置啊,从低位开始填可能会--柳暗花明又一村??

    2016-10-09 14:15:15

  • 相关阅读:
    一个例子学懂搜索引擎(lucene)
    在vs2008中设置jquery智能提示
    40个有用的jQuery技术和教程
    构建高性能ASP.NET站点之三 细节决定成败
    了解搜索引擎技术
    使用微软分布式缓存服务Velocity Part 2
    【转】构建高性能ASP.NET站点 开篇
    构建高性能ASP.NET站点之二 优化HTTP请求(前端)
    笔记:深入理解JVM 第4章 JVM性能监控与故障处理工具
    javascript 继承
  • 原文地址:https://www.cnblogs.com/Konjakmoyu/p/5942038.html
Copyright © 2020-2023  润新知