【BZOJ4542】大数(莫队)
题意:给定一个N位的由[0..9]组成的数字串和质数P,有M次不强制在线的询问,每次询问区间[l,r]中模P意义下为0的子串个数
N,M<=2e5,P<=1e10
思路:一次A,本来还以为要调好长时间……
考虑类似于字符串哈希的思路,预处理出每个后缀在模P意义下的余数,设从第i位到第N位的后缀的值为s[i]
[L,R]这段区间的值*10^(N-R)=s[L]-s[R+1]
特判P=2和P=5,因为是10进制只需要考虑最后一位能被整除,对于每一个询问计算每一位的贡献做前缀和即可
P取其他值时质数10^(N-R)与P必定互质,所以若[L,R]这段的值能被P整除,则s[L]-s[R+1]必定需要被P整除
取模后等价于[L,R+1]一段数字中相等数字对数,是经典的莫队
莫队部分好像都是先写扩大区间部分再写缩小区间部分的
条件允许的话还是要把所有细节想清楚了再写,效率会高很多
1 #include<cstdio> 2 #include<iostream> 3 #include<cmath> 4 #include<cstring> 5 #include<algorithm> 6 typedef long long ll; 7 using namespace std; 8 #define N 210000 9 10 struct node 11 { 12 int x,y,id; 13 }c[N]; 14 15 ll a[N],b[N],s[N],ans[N],pos[N],A[N]; 16 char ch[N]; 17 int n,m; 18 19 bool cmp(node a,node b) 20 { 21 if(pos[a.x]==pos[b.x]) return a.y<b.y; 22 return a.x<b.x; 23 } 24 25 void init() 26 { 27 int block=int(sqrt(N)); 28 for(int i=1;i<=N;i++) pos[i]=(i-1)/block+1; 29 } 30 31 void solve() 32 { 33 memset(s,0,sizeof(s)); 34 ll tmp=0; 35 int nowx=1; 36 int nowy=0; 37 for(int i=1;i<=m;i++) 38 { 39 while(nowx>c[i].x) 40 { 41 tmp+=s[a[nowx-1]]; 42 s[a[nowx-1]]++; 43 nowx--; 44 } 45 while(nowy<c[i].y) 46 { 47 tmp+=s[a[nowy+1]]; 48 s[a[nowy+1]]++; 49 nowy++; 50 } 51 while(nowx<c[i].x) 52 { 53 s[a[nowx]]--; 54 tmp-=s[a[nowx]]; 55 nowx++; 56 } 57 while(nowy>c[i].y) 58 { 59 s[a[nowy]]--; 60 tmp-=s[a[nowy]]; 61 nowy--; 62 } 63 ans[c[i].id]=tmp; 64 } 65 } 66 67 68 int main() 69 { 70 ll MOD; 71 scanf("%lld",&MOD); 72 scanf("%s",ch+1); 73 n=strlen(ch+1); 74 if(MOD==2||MOD==5) 75 { 76 for(int i=1;i<=n;i++) 77 if((ch[i]-'0')%MOD==0) 78 { 79 a[i]=i; b[i]=1; 80 } 81 a[0]=b[0]=0; 82 for(int i=1;i<=n;i++) 83 { 84 a[i]+=a[i-1]; 85 b[i]+=b[i-1]; 86 } 87 scanf("%d",&m); 88 for(int i=1;i<=m;i++) 89 { 90 int x,y; 91 scanf("%d%d",&x,&y); 92 ll ans=a[y]-a[x-1]-1ll*(b[y]-b[x-1])*(x-1); 93 printf("%lld\n",ans); 94 } 95 return 0; 96 } 97 a[n+1]=0; 98 ll mi=1; 99 for(int i=n;i>=1;i--) 100 { 101 a[i]=(a[i+1]+(ch[i]-'0')*mi)%MOD; 102 mi=mi*10%MOD; 103 } 104 n++; 105 for(int i=1;i<=n;i++) A[i]=a[i]; 106 sort(A+1,A+n+1); 107 A[0]=unique(A+1,A+n+1)-A-1; 108 for(int i=1;i<=n;i++) a[i]=lower_bound(A+1,A+A[0]+1,a[i])-A; 109 scanf("%d",&m); 110 for(int i=1;i<=m;i++) 111 { 112 scanf("%d%d",&c[i].x,&c[i].y); 113 c[i].y++; 114 c[i].id=i; 115 } 116 init(); 117 sort(c+1,c+m+1,cmp); 118 solve(); 119 for(int i=1;i<=m;i++) printf("%lld\n",ans[i]); 120 return 0; 121 } 122 123 124 125
null