统计区间 [1,n] 中含有 '13' 且模 13 为 0 的数字有多少个。
就是把情况用状态表示出来,几维不是问题,终点是把所有的状态表示出来。
转移就是枚举该位是多少,根据这个位是多少,改变下一个dfs的参数,转移到下一位就好
边界:注意只有当所有的情况都符合的时候,i==0时才能把方案数置为1,否则,就像这道题,如果到最后没有13,且余数不为0,那么就应该返回方案数0
#include<cstdio> #include<cstring> #include<cmath> #include<algorithm> #include<cstdlib> using namespace std; int f[11][2][2][13]; int n,li[11]; int remain[11]; int dfs(int i,bool state,bool have,int k,bool limit) { if (i==0&&k==0&&have) return 1;//边界 if (i==0) return 0; if (!limit && f[i][state][have][k]) return f[i][state][have][k];//数位dp的limit必须加,因为,在边界最大值的情况是要注意处理的 int up=limit ? li[i]:9,ans=0; for (int j=0;j<=up;j++) { int h=((k-(j*remain[i]))%13+13)%13; ans+=dfs(i-1 , j==1?true:false , have||(state&&j==3) ? true:false, h , limit&& j==up?true :false ); } if (!limit) f[i][state][have][k]=ans;//相对应上面的limit return ans; } void work(int n) { memset(f,0,sizeof(f)); memset(li,0,sizeof(li)); int tot=0; while (n) { li[++tot]=n%10; n=n/10; } printf("%d\n",dfs(tot,false,false,0,true)); } int main() { remain[1]=1; for (int i=2;i<11;i++ ) remain[i]=remain[i-1]*10%13; while (scanf("%d",&n)!=EOF) work(n); return 0; }
