洛谷 P6371 解题记录
Every "END" is a new "BEGINNING"
简单数位 dp。但不知道为什么评了紫。
一开始是以为和 [一本通 5.3 练习 1]数字游戏 2 一样,复制过来代码改了改就准备提交。
测了样例,WA。
然后才发现,我读错题了啊啊!!!题目要求是原数被 $X$ 整除,不是数字和被 $X$ 整除。
简单改了下代码,结果一堆 RE。
啊啊啊数组开小了啊啊!!!
数组开到 $4 \times {10}^8$。
啊啊啊 MLE!!!
仔细看看数据范围。
竟然 $X < {10}^{11}$。
然后发现 $X > {10}^5$ 的时候可以暴力。
简单打了打暴力。
$72$ 分。
忘记特判前导零了啊!
$93$ 分。
前导零可以有多个啊!
AC。
代码:
#include<bits/stdc++.h>
using namespace std;
long long MOD,ant[15][100005],ant2[15][100005],lg10[15],ans,a,b;
string s;
void init(){
lg10[0]=1;
for(int i=1;i<=13;i++)lg10[i]=lg10[i-1]*10;
ant[0][0]=1;
for(int i=0;i<s.size();i++)ant[1][(s[i]-48)%MOD]++;
for(int i=2;i<=11;i++){
for(int j=0;j<s.size();j++){
for(int k=0;k<MOD;k++){
ant[i][((s[j]-48)*lg10[i-1]+k)%MOD]+=ant[i-1][k%MOD];
}
}
}
ant2[0][0]=1;
for(int i=1;i<=11;i++){
for(int j=0;j<MOD;j++)ant2[i][j]=ant[i][j]+ant2[i-1][j];
}
}
void DEBUG(){
for(int i=1;i<=11;i++){
for(int j=0;j<MOD;j++)cout<<ant[i][j]<<" ";
cout<<endl;
}
}
void Sol2(){
for(long long i=MOD;i<=b;i+=MOD){
bool flag=1;
long long y=i;
if(i<a)flag=0;else
while(y){
for(int j=0;j<s.size();j++){
if(s[j]-48==y%10)break;
if(j==s.size()-1)flag=0;
}
y/=10;
}
ans+=flag;
}
cout<<ans;
exit(0);
}
int main(){
cin>>MOD>>a>>b;
cin>>s;
if(MOD>100000)Sol2();
memset(ant,0,sizeof(ant));
init();
ans=0;
int adgt=0,bdgt=0,tot=0;
b++;
while(lg10[adgt]<=a)adgt++;
while(lg10[bdgt]<=b)bdgt++;
for(int i=bdgt;i>=1;i--){
int st=b/lg10[i-1];
if(i==bdgt&&s[0]!=48)ans+=ant2[i-1][0];
for(int j=0;j<s.size()&&s[j]-48<st;j++){
ans+=ant[i-1][(MOD*1145141919810-(s[j]-48+tot)*lg10[i-1])%MOD];
}
bool flag=0;
for(int j=0;j<s.size();j++){
if(s[j]-48==st)flag=1;
}
if(!flag)break;
tot+=st;
tot*=10;
b%=lg10[i-1];
if(!b)break;
}
tot=0;
for(int i=adgt;i>=1;i--){
int st=a/lg10[i-1];
if(i==adgt&&s[0]!=48)ans-=ant2[i-1][0];
for(int j=0;j<s.size()&&s[j]-48<st;j++){
ans-=ant[i-1][(MOD*1145141919810-(s[j]-48+tot)*lg10[i-1])%MOD];
}
bool flag=0;
for(int j=0;j<s.size();j++){
if(s[j]-48==st)flag=1;
}
if(!flag)break;
tot+=st;
tot*=10;
a%=lg10[i-1];
if(!a)break;
}
cout<<ans<<endl;
}

浙公网安备 33010602011771号