hdu3652(数位DP)

做了n久才搞定,感觉自己的数位DP学的太不扎实了

题意:求1--n中能有13这个数字且能被13整除的数的数目

解释看代码:

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include

#define inf 0x7fffffff
#define eps 1e-9
#define pi acos(-1.0)
#define P system("pause")
using namespace std;
int dp[15][15][3];/* 考虑是否含有13分为三种情况;1、不含13;2、不含13并且最高位是3;3、含有13
                      但是这次还要考虑能否被13整除,所以还要加一维dp[i][j][k],i表示位数,j表示取模13得到的余数 
                      k表示1、2、3这三种情况                                                                    
                  */                                                                           
int md[15];
void init()
{
     memset(md,0,sizeof(md));
     memset(dp,0,sizeof(dp));
     int i,j,k;
     md[0] = 1;
     for(i = 1; i < 10; i++)  md[i] = (md[i-1]*10) %13;//md表示1,10,100,1000........模13的余数 
     dp[0][0][0] = 1;
     
     for(i = 1; i < 12; i++)
           for(j = 0; j < 13; j++)
           {
                 for(k = 0; k < 10; k++)
                     dp[i][(md[i-1]*k+j)%13][0] += dp[i-1][j][0];
                 dp[i][(md[i-1]+j)%13][0] -= dp[i-1][j][1];
                 dp[i][(md[i-1]*3+j)%13][1] += dp[i-1][j][0];
                 for(k = 0; k < 10; k++)
                       dp[i][(md[i-1]*k+j)%13][2] += dp[i-1][j][2];
                 dp[i][(md[i-1]+j)%13][2] += dp[i-1][j][1]; 
           }        
}
int fun(int n)
{
    int i,a[15],len = 0;
    memset(a,0,sizeof(a));
    while(n)
    {
          a[len++] = n % 10;
          n /= 10;          
    }
    int ans = 0,mod = 0,k;
    bool flag = 0;
    for(i = len - 1; i >= 0;mod = (mod + md[i]*a[i])%13,i--)
    {
          for(k = 0; k < a[i]; k++) 
                 ans += dp[i][(13- (mod + k*md[i])%13)%13][2];//i-1位中存在13的情况 
          if(flag)                                //前i+1位中已经出现了13 
             for(k = 0; k < a[i]; k++)
                  ans += dp[i][(13- (mod + k*md[i])%13)%13][0];
          if(!flag && a[i] > 3 && a[i+1] == 1)    //前一位和当前位构成13的情况
                   ans += dp[i+1][(13- mod)%13][1];
          if(!flag && a[i] > 1)//当前位和后一位构成13的情况
                   ans += dp[i][(13- (mod + md[i])%13)%13][1];
          if(a[i] == 3 && a[i+1] == 1) flag = 1;
          
    }
 //   if(flag)  ans++;   注意这里如果这样写会wa,因为没有判定是否被13整除
    return ans;
}
int main()
{
//freopen("input.txt","r",stdin);
//freopen("output.txt","w",stdout);
    init();
    int i,j;
    /*for(i = 0; i < 10; i++){
          for(j = 0; j < 13; j++)
             cout<


你可能感兴趣的:(acm之DP)