zoukankan      html  css  js  c++  java
  • 【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

  • 相关阅读:
    Bootstrap-模态框Modal使用
    MVC Controller return 格式
    数据库水平拆分和垂直拆分区别(以mysql为例)
    MySQL 对于大表(千万级),要怎么优化呢?
    mysql优化案例
    Mysql大表查询优化技巧总结及案例分析
    Mysql Partition 理论知识总结
    mysql Partition(分区)初探
    MySQL partition分区I
    xapian安装
  • 原文地址:https://www.cnblogs.com/Konjakmoyu/p/5942038.html
Copyright © 2011-2022 走看看