题目:https://vjudge.net/problem/UVA-11361
思路:数位dp,用记忆化搜索写,dp[pos][i][j][limit] 代表剩余有pos位,每位上的数字和模k 等于i, 当前总数值模k等于j,limit代表限制位。
本题还要注意的是当k》100时 答案为0,要加个特判,不然k=100000会导致内存不够。
代码(含注释):
#include<bits/stdc++.h>
#define INF 0x3f3f3f3f3f3f3f3f
#define inf 0x3f3f3f3f
#define FILL(a,b) (memset(a,b,sizeof(a)))
#define re register
#define lson rt<<1
#define rson rt<<1|1
#define lowbit(a) ((a)&-(a))
#define ios std::ios::sync_with_stdio(false);std::cin.tie(0);std::cout.tie(0);
#define fi first
#define rep(i,n) for(int i=0;(i)<(n);i++)
#define rep1(i,n) for(int i=1;(i)<=(n);i++)
#define se secondusing namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int > pii;
int dx[4]= {-1,1,0,0},dy[4]= {0,0,1,-1};
const ll mod=1000000000;
const ll N =1e5+10;
const double eps = 1e-4;
const double pi=acos(-1);
ll gcd(int a,int b){return !b?a:gcd(b,a%b);}
ll dp[20][100][11000][5];
int sum[100];
int l,r,k;
int idx;
ll dfs(int pos,int i,int j,int limit)
{if(pos==0){if(i==0&&j==0)//两者都成立时 才找到一个答案return 1;return 0;}if(dp[pos][i][j][limit]>=0) return dp[pos][i][j][limit];//之前已经搜过了ll ans=0;for(int q=0;q<(limit?sum[pos]:10);q++){ans+=dfs(pos-1,(i+q)%k,(j*10+q*)%k,0);//pos位的数比sum【pos】小,下一位没有limit}if(limit)//有limit时pos位选择最大的那个,下一位也应该有limit{ans+=dfs(pos-1,(sum[pos]+i)%k,(j*10+sum[pos])%k,1);}return dp[pos][i][j][limit]=ans;
}
ll work(int x)//把每一位上的数字保存起来
{idx=0;while(x>0){sum[++idx]=x%10;x/=10;}return dfs(idx,0,0,1);
}
void slove()
{cin>>l>>r>>k;if(k>100) {//大于100时直接输出cout<<0<<endl;return;}FILL(dp,-1);cout<<work(r)-work(l-1)<<endl;//经典算法了,两前缀相减等于区间和。// cout<<fixed<<setprecision(7)<<dp[n]<<endl;
}
int main()
{iosint t=1;cin>>t;fun();while(t--){slove();}return 0;
}