LightOJ 1068 Investigation(记忆化搜索)

题目链接:http://www.lightoj.com/volume_showproblem.php?problem=1068

题意:给出区间[A,B]一个数K。求区间中能被K整数且各位数字之和也能被K整除的数的个数。

思路:总的思路是,由于数字都小于2^31,所以最多10位,也就是各位数字之和最多为90,也就是K大于90时答案必定为0。因此只需要考虑K小于等于90的情况。我是这样考虑的f[i][j][k]表示前i位数个位数字之和为j模K的余数为k的数量。DP即可。

 

下面的第一份代码是我的思路。第二份是网上看别人的。。。

 

View Code
  1 #include <iostream>

  2 #include <cstdio>

  3 #include <cstring>

  4 using namespace std;

  5 

  6 int C,num=0;

  7 int f[15][100][100],a[15];

  8 int A,B,K;

  9 

 10 int getCount(int x)

 11 {

 12     int t=0,i,k;

 13     while(x)

 14     {

 15         a[++t]=x%10;

 16         x/=10;

 17     }

 18     for(i=1;i<=t/2;i++)

 19     {

 20         k=a[i];

 21         a[i]=a[t+1-i];

 22         a[t+1-i]=k;

 23     }

 24     return t;

 25 }

 26 

 27 int DP1(int t,int x)

 28 {

 29     if(t==0) return 0;

 30     int i,j,k,p;

 31     memset(f,0,sizeof(f));

 32     for(i=1;i<=9;i++) f[1][i][i%x]++;

 33     for(i=2;i<=t;i++) for(j=1;j<=(i-1)*9;j++) for(k=0;k<x;k++) if(f[i-1][j][k])

 34     {

 35         for(p=0;p<=9;p++) f[i][j+p][(k*10+p)%x]+=f[i-1][j][k];

 36     }

 37     int ans=0;

 38     for(i=1;i<=t;i++) for(j=x;j<=90;j+=x) ans+=f[i][j][0];

 39     return ans;

 40 }

 41 

 42 int DP(int t,int x,int low[],int high[])

 43 {

 44     if(t==0) return 0;

 45     int i,j,k,p;

 46     memset(f,0,sizeof(f));

 47     for(i=low[1];i<=high[1];i++) f[1][i][i%x]++;

 48     for(i=2;i<=t;i++) for(j=1;j<=(i-1)*9;j++) for(k=0;k<x;k++) if(f[i-1][j][k])

 49     {

 50         for(p=low[i];p<=high[i];p++)

 51             f[i][j+p][(k*10+p)%x]+=f[i-1][j][k];

 52     }

 53     int ans=0;

 54     for(j=x;j<=90;j+=x) ans+=f[t][j][0];

 55     return ans;

 56 }

 57 

 58 int OK(int x)

 59 {

 60     if(x%K) return 0;

 61     int t=0;

 62     while(x) t+=x%10,x/=10;

 63     return t%K==0;

 64 }

 65 

 66 int cal(int x)

 67 {

 68     if(x==0) return 0;

 69     int t=getCount(x),low[15],high[15],i;

 70     for(i=1;i<=10;i++)

 71     {

 72         low[i]=0;

 73         high[i]=9;

 74     }

 75     low[1]=1;

 76     int ans=DP1(t-1,K);

 77     for(i=1;i<=t;i++)

 78     {

 79         low[i-1]=++high[i-1];

 80         high[i]=a[i]-1;

 81         ans+=DP(t,K,low,high);

 82     }

 83     return ans+OK(x);

 84 }

 85 

 86 int main()

 87 {

 88     for(scanf("%d",&C);C--;)

 89     {

 90         scanf("%d%d%d",&A,&B,&K);

 91         int ans;

 92         if(K>90) ans=0;

 93         else ans=cal(B)-cal(A-1);

 94         printf("Case %d: %d\n",++num,ans);

 95     }

 96     return 0;

 97 }

 98 

 99 #include <iostream>

100 #include <cstdio>

101 #include <cstring>

102 using namespace std;

103 

104 int C,num=0;

105 int f[15][100][100][2];

106 int A,B,K,len;

107 char s[20];

108 

109 int DFS(int dep,int mod1,int mod2,int flag)

110 {

111     if(dep==len) return !mod1&&!mod2;

112     int &ans=f[dep][mod1][mod2][flag];

113     if(ans!=-1) return ans;

114     ans=0;

115     int i,t=s[dep]-'0';

116     for(i=0;i<10;i++)

117     {

118         if(flag&&i>t) break;

119         ans+=DFS(dep+1,(mod1*10+i)%K,(mod2+i)%K,i<t?0:flag);

120     }

121     return ans;

122 }

123 

124 int cal(int x)

125 {

126     if(K==1) return x;

127     sprintf(s,"%d",x);

128     len=strlen(s);

129     memset(f,-1,sizeof(f));

130     return DFS(0,0,0,1);

131 }

132 

133 int main()

134 {

135     for(scanf("%d",&C);C--;)

136     {

137         scanf("%d%d%d",&A,&B,&K);

138         int ans;

139         if(K>90) ans=0;

140         else ans=cal(B)-cal(A-1);

141         printf("Case %d: %d\n",++num,ans);

142     }

143     return 0;

144 }

 

 

 

你可能感兴趣的:(IO)