题目链接:https://vjudge.net/contest/372594#problem/B
题意:给出m和d,a和b,找出a到b之间的所有偶数位为d,所有奇数位不为d的数,且要求这个数为m的倍数
解题思路:
①注意a和b长度可能达到2000,用字符串保存
②利用dp[pos][mmod]表示pos位置处余数为mmod的数的个数,在进行数位dp过程中注意前缀0情况和有上限情况。
下面是我自己写的代码,但不明白为什么超时了
#include<iostream>
#include<cstdio>
#include<string>
using namespace std;
const int mod=1e9+7;
#define ll long long
int n,m;
int t=0;
int dp[2100][2100];
int num[2100];
char a[2200],b[2200];
//flag表示奇偶数 pre表示前缀0情况 mmod表示取余m后的余数
int solve(int pos,int len,int limit,int mmod,int flag,int pre)
{
if(pos<0)
return mmod==0;
if(!limit&&dp[pos][mmod])
return dp[pos][mmod];
int up=limit?num[pos]:9;
int ans=0;
for(int i=0;i<=up;i++){
if(flag==0&&i==n) continue;
if(flag==1&&i!=n) continue;
if(pre==0&&i==0)
ans+=solve(pos-1,len,limit&&i==up,(mmod*10+i)%m,flag^1,0);
else
ans+=solve(pos-1,len,limit&&i==up,(mmod*10+i)%m,flag^1,1);
ans%=mod;
}
if(!limit)
dp[pos][mmod]=ans;
return ans;
}
void helper(int len)
{
for(int i=0;i<len;i++)
if(num[i]){
num[i]--;
break;
}
else
num[i]=9;
}
int cal(char* s)
{
int len=strlen(s);
for(int i=len-1;i>=0;i--)
{
num[len-1-i]=s[i]-'0';
}
if(!t)
helper(len),t++;
return solve(len-1,len,1,0,0,0);
}
int main()
{
scanf("%d%d",&m,&n);
scanf("%s",a); scanf("%s",b);
int ans1=cal(a);
int ans2=cal(b);
printf("%d\n",(ans2-ans1+mod)%mod);
return 0;
}
这个是我看到的ac的代码(不是我自己写的,我转载别人的)
#include<iostream>
#include<cstdio>
#include<string>
using namespace std;
using namespace std;
typedef long long ll;
const ll mod = 1e9+7;
const int n = 2020;
char a[n], b[n];
int m, n;
int dg[n];
ll f[n][n];
inline ll add(ll x, ll y) {
x = x + y;
return x >= mod ? x-mod : x;
}
ll dfs(int i, int s, bool flag, bool e) { // dp[i][s] , flag 表示奇数还是偶数,e代表边界
if(i == -1) return s == 0;
if(!e && ~f[i][s]) return f[i][s];
ll res = 0ll;
int u = e ? dg[i] : 9;
for(int d = 0; d <= u; ++d) {
if(flag == 1 && d == n) continue;
if(flag == 0 && d != n) continue;
res = add(res, dfs(i-1, (s*10+d)%m, flag^1, e && d==u));
}
return e ? res : f[i][s] = res;
}
void deal(int& len) {
for(int i = 0; i < len; ++i) {
if(dg[i] == 0) dg[i] = 9;
else {
--dg[i];
break;
}
}
return ;
}
ll solve(char c[], bool fg) {
int len = strlen(c);
for(int i = 0; i < len; ++i) dg[i] = c[len-1-i] - '0';
if(fg) deal(len);
return dfs(len-1, 0, 1, 1);
}
int main()
{
scanf("%d %d", &m, &n);
scanf("%s %s", a, b);
memset(f, -1, sizeof f);
printf("%i64d\n", add(solve(b, 0) - solve(a, 1), mod));
return 0;
}