HNOI2016 大数(number)<莫队>
2016-04-30 15:04
375 查看
题目
分析
一道典型的莫队。先预处理出后缀,即f[i]表示i~(n-1) mod p 的值.
但p的值不小,显然不能直接存,加一个离散化。
观察题目,发现一串数s(l~r)整除p满足s(l~n-1)%p==s(r+1~n-1)%p
但p值为2或5不满足这个性质需要特判(不过数据中好像没有,于是笔者没写,有兴趣的可以自己去写写。。。。。。)
然后问题转化为求一段区间中有几对相等的f值。
套一个莫队。(ans(l,r)可以由【ans(l+1,r),ans(l-1,r),ans(l,r+1),ans(l,r-1)】推出,为保证时间复杂度,用个分块【因为不会曼哈顿树】)。
注意:要在数列的后面加一个f值为0。
代码
#include<cstdio> #include<iostream> #include<algorithm> #include<cmath> #include<cstring> #define ll long long using namespace std; const int maxn=200000+10; char a[maxn]; ll p,n,m,s[maxn],_10[maxn]/*_10[i]表示10的i次方modp*/,f[maxn]/*f[i]表示i~l mod p 的值*/,cd[maxn]; ll cur,sum[maxn],kuai,ans[maxn]; struct query { ll t,x,y; }q[maxn]; //把每个区间(l,r)看成一个点(x,y),相同块中的点按y排序,否则按x排序,可以保证n^1.5的时间复杂度 bool operator < (const query& a,const query& b){ if(a.x/kuai==b.x/kuai) return a.y<b.y; else return a.x<b.x; } int main() { //freopen("number.in","r",stdin); //freopen("number.out","w",stdout); cin>>p; _10[0]=1;//其实这个_10数组可以只用一个变量 _10[1]=10%p; for(int i=2;i<maxn;i++){ _10[i]=(_10[i-1]*_10[1])%p; } char c; scanf("%s",a); n=strlen(a); kuai=(ll)sqrt((double)n);//按x坐标分块,kuai表示没段块的长度 cin>>m; for(int i=1;i<=m;i++) scanf("%lld%lld",&q[i].x,&q[i].y),q[i].x--,q[i].t=i; sort(q+1,q+m+1); for(int i=0;i<n;i++) s[i]=a[i]-'0'; f[n-1]=s[n-1]%p; cd[n-1]=f[n-1]; for(int i=n-2;i>=0;i--){ f[i]=(f[i+1]+(_10[n-i-1]*s[i])%p)%p; cd[i]=f[i]; } //for(int i=0;i<n;i++) printf("%lld ",f[i]);printf("\n"); //离散化 cd =0; sort(cd,cd+n+1); int tot=0; for(int i=1;i<=n;i++){ if(cd[i]!=cd[tot]) cd[++tot]=cd[i]; } for(int i=0;i<n;i++) { int mid,l=0,r=tot; while(l<r) //在ad中找到f的位置 { mid=(l+r)>>1; if(cd[mid]<f[i]) l=mid+1; else r=mid; } f[i]=l; } //*********************************************** int l,r; l=1;r=0; for(int i=1;i<=m;i++) { while(r<q[i].y) cur+=sum[f[++r]]++; while(l>q[i].x) cur+=sum[f[--l]]++; while(r>q[i].y) cur-=--sum[f[r--]]; while(l<q[i].x) cur-=--sum[f[l++]]; ans[q[i].t]=cur; } for(int i=1;i<=m;i++) printf("%lld\n",ans[i]); return 0; } /* 样例: 11 121121 3 1 6 1 5 1 4 */
相关文章推荐
- [BZOJ2038][2009国家集训队][莫队][分块]小z的袜子
- Codeforces538F A Heap of Heaps【分块+差分求前缀和】
- 大矩阵的分块乘法及matlab实现
- Hadoop分块和分片
- bzoj-2741 L
- bzoj-3585 mex
- bzoj-2051 A Problem For Fun
- 算法马拉松8(差和问题)
- 1290 Counting Diff Pairs
- 【Violet 6】【BZOJ2724】蒲公英
- 【BZOJ4320】Homework
- 【BZOJ4216】Pig
- 【BZOJ2741】FOTILE模拟赛 L
- [2009国家集训队]小Z的袜子(hose) 分块做法
- NBUT 1457 分块
- codeforces #307 E. GukiZ and GukiZiana (分块)
- Codeforces Round #307 (Div. 2)E. GukiZ and GukiZiana(分块)
- 【分块】 CF 551 E GukiZ and GukiZiana
- BZOJ 2038 小Z的袜子(hose) (莫队离线)
- 关于分块的简单介绍