2 条题解

  • 0
    @ 2025-10-8 17:10:07
    #include<bits/stdc++.h>
    using namespace std;
    #define int long long
    const int N=1e6;
    int k,p,q,r,cnt,ans,jl;
    char s;
    int xl[N],fst[N],lst[N],qzh[N],ac[N];//fst 记录第一段成立情况的位置,lst 记录第三段成立情况的位置 
    int cf(int x){
    	jl=(jl*10)%r;
    	return jl;
    }
    signed main(){
    	cin>>k>>p>>q>>r;
    	for(int i=1;i<=k;i++){//使用 char 类型来读入无空格数据 
    		cin>>s;
    		xl[i]=s-'0';
    	}
    	ac[0]=1;
    	for(int i=1;i<=k;i++){//预处理余数,qzh 记录由 1~i 位组成的数取余q的结果,ac 记录 10^i 取余 q 的结果,用取余运算的结合律来 O(1) 求余数 
    		qzh[i]=(qzh[i-1]*10+xl[i])%q;
    		ac[i]=(ac[i-1]*10)%q;
    	}
    	for(int i=1;i<=k;i++){//枚举第一段 
    		cnt=(cnt*10+xl[i])%p;
    		if(!cnt){
    			fst[++fst[0]]=i;
    		}
    	}
    	cnt=0,jl=1;
    	for(int i=k;i>=1;i--){//枚举第三段 
    		cnt=(cnt+xl[i]*cf(k-i))%r; 
    		if(!cnt&&(xl[i]||i==k)){
    			lst[++lst[0]]=i;
    		}
    	}
    	for(int i=1;i<=fst[0];i++){//判断第二段 
    		for(int j=lst[0];j>=1;j--){
    			if(fst[i]>=lst[j]-1){//优化,以免多次访问相交情况
    				lst[0]--;
    				continue;
    			}
    			if(!xl[fst[i]+1]&&fst[i]<lst[j]-2){//优化以免多次访问有前导 0 情况
    				break;
    			}
    			if(!((qzh[lst[j]-1]-qzh[fst[i]]*ac[lst[j]-fst[i]-1]+q)%q)){//成立,使用前缀和预处理余数,同样使用取余运算的结合律 
    				ans++;
    			}
    		}
    	}
    	cout<<ans;
    	return 0;
    }
    
    • 0
      @ 2025-10-8 17:09:58
      #include<bits/stdc++.h>
      using namespace std;
      #define int long long
      const int N=1e6;
      int k,p,q,r,cnt,ans,jl;
      char s;
      int xl[N],fst[N],lst[N],qzh[N],ac[N];//fst 记录第一段成立情况的位置,lst 记录第三段成立情况的位置 
      int cf(int x){
      	jl=(jl*10)%r;
      	return jl;
      }
      signed main(){
      	cin>>k>>p>>q>>r;
      	for(int i=1;i<=k;i++){//使用 char 类型来读入无空格数据 
      		cin>>s;
      		xl[i]=s-'0';
      	}
      	ac[0]=1;
      	for(int i=1;i<=k;i++){//预处理余数,qzh 记录由 1~i 位组成的数取余q的结果,ac 记录 10^i 取余 q 的结果,用取余运算的结合律来 O(1) 求余数 
      		qzh[i]=(qzh[i-1]*10+xl[i])%q;
      		ac[i]=(ac[i-1]*10)%q;
      	}
      	for(int i=1;i<=k;i++){//枚举第一段 
      		cnt=(cnt*10+xl[i])%p;
      		if(!cnt){
      			fst[++fst[0]]=i;
      		}
      	}
      	cnt=0,jl=1;
      	for(int i=k;i>=1;i--){//枚举第三段 
      		cnt=(cnt+xl[i]*cf(k-i))%r; 
      		if(!cnt&&(xl[i]||i==k)){
      			lst[++lst[0]]=i;
      		}
      	}
      	for(int i=1;i<=fst[0];i++){//判断第二段 
      		for(int j=lst[0];j>=1;j--){
      			if(fst[i]>=lst[j]-1){//优化,以免多次访问相交情况
      				lst[0]--;
      				continue;
      			}
      			if(!xl[fst[i]+1]&&fst[i]<lst[j]-2){//优化以免多次访问有前导 0 情况
      				break;
      			}
      			if(!((qzh[lst[j]-1]-qzh[fst[i]]*ac[lst[j]-fst[i]-1]+q)%q)){//成立,使用前缀和预处理余数,同样使用取余运算的结合律 
      				ans++;
      			}
      		}
      	}
      	cout<<ans;
      	return 0;
      }
      • 1

      信息

      ID
      5942
      时间
      1000ms
      内存
      256MiB
      难度
      10
      标签
      递交数
      1
      已通过
      1
      上传者