2 1 10 1 20
Case #1: 0 Case #2: 1HintThe answer maybe very large, we recommend you to use long long instead of int.
题意:求出区间内每位之和能被10整除的数的个数
思路:这题是简单的数位DP,当然用规律也能破
#include <stdio.h> #include <string.h> #include <algorithm> using namespace std; __int64 bit[20]; __int64 dp[20][10]; //dp[i][j],长度为i的数与10模为j的个数 __int64 solve(__int64 n) { __int64 ans; __int64 tem1 = n,len,sum,i,x,j,k; len = sum = ans = 0; memset(dp,0,sizeof(dp)); while(tem1) { bit[++len] = tem1%10; tem1/=10; } for(i = 1; i<=len/2; i++)//按高位在头排列 { int t; t = bit[i]; bit[i] = bit[len-i+1]; bit[len-i+1] = t; } x = 0; for(i = 1; i<=len; i++)//从最高位开始 { for(j = 0; j<10; j++)//将高位的全部枚举一次 for(k = 0; k<10; k++) dp[i][(j+k)%10]+=dp[i-1][j]; for(j = 0; j<bit[i]; j++)//枚举该位的数字到界限 dp[i][(x+j)%10]++; x = (x+bit[i])%10; } if(!x) dp[len][0]++; return dp[len][0]; } int main() { __int64 T,l,r,cas = 1; __int64 ans; scanf("%I64d",&T); while(T--) { ans = 0; scanf("%I64d%I64d",&l,&r); ans = solve(r)-solve(l-1); printf("Case #%I64d: %I64d\n",cas++,ans); } return 0; }
而且通过观察我们可以发现,每个数从0到该位数字中,每位和能被10整除的个数是该数字除以10,然后再枚举各位到界限的个数之和
于是可得以下代码
#include <stdio.h> #include <string.h> #include <algorithm> using namespace std; __int64 solve(__int64 n) { if(n<0) return 0; __int64 t = n/100,i,ans = 0,sum; ans = t*10; for(i = t*100;i<=n;i++) { sum = 0; __int64 tem = i; while(tem) { sum+=tem%10; tem/=10; } if(sum%10 == 0) ans++; } return ans; } int main() { __int64 T,l,r,cas = 1,ans; scanf("%I64d",&T); while(T--) { scanf("%I64d%I64d",&l,&r); ans = solve(r)-solve(l-1); printf("Case #%I64d: %I64d\n",cas++,ans); } return 0; }