CF628D Magic Numbers

Posted sto324

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了CF628D Magic Numbers相关的知识,希望对你有一定的参考价值。

题目描述

给你两个数m和d

再给你两个数lr

询问区间[l,r]中有多少个数满足偶数位是d奇数位不是d且为m的倍数的数(位数从左数)

1 <=m <= 2000 , 0 <= d <=9

l <= r <= 10 ^ 2000

保证a<=b且a和b位数相同

题解

一开始一直在考虑前导零,讨论贼麻烦,后来看题解发现都没考虑前导零,一看英文题目才发现位数相同。还有奇数位不能为d也不知道。(还是多学英语好)

那么就很简单了,直接f[s][sum]当前枚举第s位,当前数mod m=sum

读入是字符,所以直接特判l方便一点,而且如果l-1位数少了的话可能会出问题。

技术图片
#include<bits/stdc++.h>
using namespace std;

const int mod=1000000007;
const int maxn=2005;
int m,d;
int len,num[maxn];
int f[maxn][maxn];
char l[maxn],r[maxn];

int dfs(int s,int sum,int lim)
    if(!s) return !sum;
    if(!lim&&f[s][sum]!=-1) return f[s][sum];
    int mx= lim ? num[s] : 9 ;
    int ret=0;
    for(int i=0;i<=mx;i++)
        if((len-s)&1) if(i!=d) continue;
        else if(i==d) continue;
        ret=(ret+dfs(s-1,(sum*10+i)%m,lim&&i==mx))%mod;
    
    if(!lim) f[s][sum]=ret;
    return ret;


bool check()
    int x=0;
    for(int i=len;i;i--)
        if((len-i)&1)if(num[i]!=d) return false;
        else if(num[i]==d) return false;
        x=(x*10+num[i])%m;
    
    return !x;


int cx()
    memset(f,-1,sizeof(f));
    len=strlen(r+1);
    for(int i=1;i<=len;i++) num[i]=r[len-i+1]-0;
    int temp2=dfs(len,0,true);
    len=strlen(l+1);
    for(int i=1;i<=len;i++) num[i]=l[len-i+1]-0;
    int temp1=dfs(len,0,true);
    int ans=temp2-temp1;
    ans+=check();
    return ans;


int main()
    scanf("%d%d",&m,&d);
    scanf("%s%s",l+1,r+1);
    printf("%d",(cx()%mod+mod)%mod);
View Code

如果位数不相同的话,那就要开两维:当前是否是奇数位,是否有前导零。

考虑只记录是否是奇数位转移是否正确,首先如果记忆化的话当前位和sum一定是一样的,那么如

00xxxx...

0000xx...

如果第一种有一种填法,第二种只要照着填就好了。

这道题还好,因为d不会填到第一位所以也不需要考虑d=0。那么如果是偶数位直接填d;不然的话就枚举,不能取d,如果没有前导零或者这一位没填0那么下一位的位数的奇偶性就要改变,不然不变。

技术图片
#include<bits/stdc++.h>
using namespace std;

const int mod=1000000007;
const int maxn=2005;
int m,d;
int len,num[maxn];
int f[maxn][maxn][2][2];
char l[maxn],r[maxn];

int dfs(int s,int sum,int lim,bool even,bool qdl)
    if(!s) return !sum&&!qdl;
    if(!lim&&f[s][sum][even][qdl]!=-1) return f[s][sum][even][qdl];
    int mx= lim ? num[s] : 9 ;
    int ret=0;
    if(!even)
        if(lim&&mx<d) return 0;
        ret=dfs(s-1,(sum*10+d)%m,lim&&d==mx,!even,false);
        if(!lim) f[s][sum][even][qdl]=ret;
        return ret;
    
    for(int i=0;i<=mx;i++)
        if(i==d) continue;
        if(qdl&&!i) ret=(ret+dfs(s-1,sum*10%m,lim&&i==mx,even,true))%mod;
        else ret=(ret+dfs(s-1,(sum*10+i)%m,lim&&i==mx,!even,false))%mod;
    
    if(!lim) f[s][sum][even][qdl]=ret;
    return ret;


bool check()
    int x=0;
    for(int i=len;i;i--)
        if((len-i)&1)if(num[i]!=d) return false;
        else if(num[i]==d) return false;
        x=(x*10+num[i])%m;
    
    return !x;


int cx()
    memset(f,-1,sizeof(f));
    len=strlen(r+1);
    for(int i=1;i<=len;i++) num[i]=r[len-i+1]-0;
    int temp2=dfs(len,0,true,true,true);
    len=strlen(l+1);
    for(int i=1;i<=len;i++) num[i]=l[len-i+1]-0;
    int temp1=dfs(len,0,true,true,true);
    int ans=temp2-temp1;
    ans+=check();
    return ans;


int main()
    scanf("%d%d",&m,&d);
    scanf("%s%s",l+1,r+1);
    printf("%d",(cx()%mod+mod)%mod);
View Code

全0有特判,不然当l=1时0合法,从rdfs时当d=0时0就不合法。

写了r-(l-1)的代码,但是不知道为啥挂了,好像是因为从l-1得到的答案更大。

技术图片
#include<bits/stdc++.h>
using namespace std;

const int mod=1000000007;
const int maxn=2005;
int m,d;
int len,num[maxn];
int f[maxn][maxn][2][2];
char l[maxn],r[maxn];

int dfs(int s,int sum,int lim,bool even,bool qdl)
    if(!s) return !sum&&!qdl;
    if(!lim&&f[s][sum][even][qdl]!=-1) return f[s][sum][even][qdl];
    int mx= lim ? num[s] : 9 ;
    int ret=0;
    if(!even)
        if(lim&&mx<d) return 0;
        ret=dfs(s-1,(sum*10+d)%m,lim&&d==mx,!even,false);
        if(!lim) f[s][sum][even][qdl]=ret;
        return ret;
    
    for(int i=0;i<=mx;i++)
        if(i==d) continue;
        if(qdl&&!i) ret=(ret+dfs(s-1,sum*10%m,lim&&i==mx,even,true))%mod;
        else ret=(ret+dfs(s-1,(sum*10+i)%m,lim&&i==mx,!even,false))%mod;
    
    if(!lim) f[s][sum][even][qdl]=ret;
    return ret;


int cx()
    memset(f,-1,sizeof(f));
    len=strlen(r+1);
    for(int i=1;i<=len;i++) num[i]=r[len-i+1]-0;
    int temp2=dfs(len,0,true,true,true);
    memset(f,-1,sizeof(f));
    len=strlen(l+1);
    for(int i=1;i<=len;i++) num[i]=l[len-i+1]-0;
    num[1]--;
    for(int i=1;i<=len;i++)
        if(num[i]>=0)break;
        num[i]+=10;
        num[i+1]--;
    
    if(!num[len]) len--;
    int temp1=dfs(len,0,true,true,true);
    int ans=temp2-temp1;
    return ans;


int main()
    scanf("%d%d",&m,&d);
    scanf("%s%s",l+1,r+1);
    printf("%d",(cx()%mod+mod)%mod);
qwq

 有谁知道帮帮我(orz)

以上是关于CF628D Magic Numbers的主要内容,如果未能解决你的问题,请参考以下文章

CodeForces 628D Magic Numbers (数位DP)

CF1110E Magic Stones - 差分

E. Magic Stones CF 思维题

CF1110E Magic Stones

CF922B Magic Forest

CF1110E Magic Stones