【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          

 

posted on 2018-11-07 23:26  myx12345  阅读(155)  评论(0编辑  收藏  举报

导航