1. 程式人生 > >【BZOJ4542】大數(莫隊)

【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