CF628D Magic Numbers
Posted sto324
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了CF628D Magic Numbers相关的知识,希望对你有一定的参考价值。
题目描述
给你两个数m和d
再给你两个数l,r
询问区间[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);
如果位数不相同的话,那就要开两维:当前是否是奇数位,是否有前导零。
考虑只记录是否是奇数位转移是否正确,首先如果记忆化的话当前位和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);
全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);
有谁知道帮帮我(orz)
以上是关于CF628D Magic Numbers的主要内容,如果未能解决你的问题,请参考以下文章