CF628D Magic Numbers (数据大+数位dp)求[a,b]中,偶数位的数字都是d,其余为数字都不是d,且能被m整除的数的个数

题意求[a,b]中,偶数位的数字都是d,其余为数字都不是d,且能被m整除的数的个数(这里的偶数位是的是从高位往低位数的偶数位)。a,b<10^2000,m2000,0da,b<10^2000,m≤2000,0≤d≤9

题解:用f[i][j]表示有i+1位,第i位是d,且%m=j的数的个数。(这个状态可能有点奇怪,不过比较便于转移)然后转移方式还是惯用的方法,判一下如果原数的偶数位不是d或者奇数位是d则停止计算即可。

自主AC开心

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
typedef long long ll;
const int maxn=2010;
const ll mod=1e9+7;
ll dp[maxn][maxn];
char a[maxn], b[maxn];
int wei[maxn], m, d;
 
ll dfs(int pos, ll sum, bool limit, int len){
    if(pos==-1) return sum==0;
    if(!limit && dp[pos][sum]!=-1) return dp[pos][sum];
    
    ll ans=0; 
    int up= limit ? wei[pos] : 9;
    for(int i=0; i<=up; i++)
    {
        if((len-pos)%2==0 && i!=d) continue;
        if((len-pos)%2==1 && i==d) continue;
        ans=(ans%mod+dfs(pos-1, (sum*10+i)%m, limit&&(i==wei[pos]), len)%mod)%mod;
    }
    
    return limit ? ans : dp[pos][sum]=ans;
}
 
ll solve(char *s){
    int len=strlen(s);
    
    for(int i=0; i<len; i++)
    {
        wei[i]=s[len-i-1]-'0';
    }
    
    return dfs(len-1, 0, true, len);
}
 
bool check(){
    int len=strlen(a);
    ll s=0;
    for(int i=0; i<len; i++)
    {
        s=(s*10+a[i]-'0')%m;
        if((i+1)%2==0 && a[i]-'0'!=d || (i+1)%2==1 && a[i]-'0'==d)
            return false;
    }
    if(!s) 
        return true;
    else
        return false;
}
 
int  main(){
    memset(dp, -1, sizeof(dp));
    
    scanf("%d%d", &m, &d);
    scanf("%s%s", a, b);
    
    ll ans=solve(b)-solve(a);
 
    if(check()){//判断a是否合格
        ans++;
    }
    ans=(ans+mod)%mod;
    printf("%lld
", ans);
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/shuaihui520/p/9968148.html