https://vjudge.net/problem/UVA-11361
菜鸡不会啊,借鉴网上的代码才知道还可以这么定义状态。
题意:计算区间[A,B]之间有多少数满足是k的倍数,并且各位数之和也是k的倍数。
设dp[len][[i][j]代表长度为len各位和模k等于j,自身模k等于i时的方案,很容易就可有推出dp[i+1][(j*10+x)%k][(s+x)%k]+=dp[i][j][s];
我自己一开始写的时候只是考虑了当前位之前的答案,没考虑到当前位,最后才发现。。。。。。
这个代码比较巧妙的时在考虑当前位的时候一块就设置了初态
#include<iostream> #include<iomanip> #include<cstring> #include<sstream> #include<algorithm> #include<cstdio> #include<cmath> #include<stdlib.h> #include<string> #include<queue> #include<vector> #include<map> #include<stack> //#include<bits/stdc++.h> #define _for(i,a,b) for(int i=a;i<=b;i++) using namespace std; typedef long long ll; const int mod =1e6+7; double esp=1e-6; int INF =0x3f3f3f3f; const int inf = 1<<28; const int MAXN=1e5+10; ll Dp[11][110][110]; int Po[11]; void Break(ll n) { Po[0] = 0; stack<int>ST; while(n) { ST.push(n%10); n /= 10; } while(!ST.empty()) { Po[++Po[0]] = ST.top(); ST.pop(); } } ll Opera(ll n , ll m) { memset(Dp,0,sizeof(Dp)); Break(n); ll ans =0 ,ant = 0; // for(int i=0;i<=9;i++) // { // Dp[1][i%m][i%m]++; // } for(int i = 1;i<=Po[0];i++) { for(int j = 0;j<m;j++) { for(int k = 0;k<m;k++) { for(int s = 0;s<=9;s++) { Dp[i][(j+s)%m][(k*10+s)%m]+=Dp[i-1][j][k];//当前位之前的数目 } } } for(int j = 0;j<Po[i];j++) { Dp[i][(ans+j)%m][(ant*10+j)%m]++;//当前位自身数目 } ans = (ans+Po[i])%m; ant = (ant*10+Po[i])%m; } if(ans==0&&ant==0) { Dp[Po[0]][0][0]++;//最后如果满足条件结果++ } return Dp[Po[0]][0][0]; } int main() { ll n,m,k; int T; scanf("%d",&T); while(T--) { scanf("%lld %lld %lld",&n,&m,&k); if(k>=100) { printf("0\n"); } else { printf("%lld\n",Opera(m,k)-Opera(n-1,k)); } } }