[HNOI2016]大数
Posted Z-Y-Y-S
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[HNOI2016]大数相关的知识,希望对你有一定的参考价值。
题目描述
小 B 有一个很大的数 S,长度达到了 N 位;这个数可以看成是一个串,它可能有前导 0,例如00009312345。小B还有一个素数P。现在,小 B 提出了 M 个询问,每个询问求 S 的一个子串中有多少子串是 P 的倍数(0 也是P 的倍数)。例如 S为0077时,其子串 007有6个子串:0,0,7,00,07,007;显然0077的子串007有6个子串都是素数7的倍数。
输入输出格式
输入格式:
第一行一个整数:P。第二行一个串:S。第三行一个整数:M。接下来M行,每行两个整数 fr,to,表示对S 的子串S[fr...to]的一次询问。注意:S的最左端的数字的位置序号为 1;例如S为213567,则S[1]为 2,S[1...3]为 213。N,M<=100000,P为素数
输出格式:
输出M行,每行一个整数,第 i行是第 i个询问的答案。
输入输出样例
11 121121 3 1 6 1 5 1 4
5 3 2 //第一个询问问的是整个串,满足条件的子串分别有:121121,2112,11,121,121。
说明
2016.4.19新加数据一组
把每一个后缀i~n的值%p算出来lst[i]
一个子串整除p满足:lst[i]=lst[j+1] (j>=i)
所以用莫队处理询问,每一次移动都是很好计算的
r向右走一步,相当于加上当前与lst[++r]相同的值ss[lst[++r]],在ss[lst[++r]]++
r向左走一步,相当于减去当前与lst[r]相同的值ss[lst[r]]--,再把r--
l相似
注意上面的条件和下面的莫队处理的都是lst[i]=lst[j+1],所以要把询问的右端点+1
还有要注意的,当p=2或p=5时要特判(不这样对不了)
这两个素数比较特殊
只要i能整除p,那么所有j~i都能整除p
用ss[]表示 前缀有多少个可以被p整除的子串 ls[]表示有多少个可以被P整除的数 求区间多少个子串的时候用ss[r]-ss[l-1]-(l-1中整除p对区间l~r的贡献)
=ss[r]-ss[l-1]-(l-1)*(ls[r]-ls[l-1])
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<cmath> 6 #include<map> 7 using namespace std; 8 typedef long long ll; 9 struct Ask 10 { 11 ll id,l,r; 12 }q[100005]; 13 ll sqn,m,n,lst[100005],ls[100005],ans[100005]; 14 ll ss[100005]; 15 map<ll,ll>Map; 16 char s[100005]; 17 bool cmp(Ask a,Ask b) 18 { 19 if (a.l/sqn==b.l/sqn) 20 return a.r<b.r; 21 return a.l/sqn<b.l/sqn; 22 } 23 ll p; 24 int main() 25 {ll bt,i,l,r; 26 cin>>p; 27 cin>>s+1; 28 cin>>m; 29 n=strlen(s+1); 30 sqn=sqrt(n); 31 bt=1; 32 if (p!=2&&p!=5) 33 { 34 for (i=n;i>=1;i--) 35 { 36 bt=bt*10%p; 37 lst[i]=(lst[i+1]+(s[i]-‘0‘)*bt)%p; 38 ls[i]=lst[i]; 39 } 40 sort(ls+1,ls+n+1); 41 for (i=1;i<=n+1;i++) 42 Map[ls[i]]=i; 43 for (i=1;i<=n+1;i++) 44 lst[i]=Map[lst[i]]; 45 for (i=1;i<=m;i++) 46 { 47 scanf("%lld%lld",&q[i].l,&q[i].r); 48 q[i].r++; 49 q[i].id=i; 50 } 51 sort(q+1,q+m+1,cmp); 52 int l=1,r=0; 53 long long cnt=0; 54 for (i=1;i<=m;i++) 55 { 56 while (r<q[i].r) cnt+=ss[lst[++r]]++; 57 while (r>q[i].r) cnt-=--ss[lst[r--]]; 58 while (l>q[i].l) cnt+=ss[lst[--l]]++; 59 while (l<q[i].l) cnt-=--ss[lst[l++]]; 60 ans[q[i].id]=cnt; 61 } 62 for (i=1;i<=m;i++) 63 printf("%lld\n",ans[i]); 64 } 65 else 66 { 67 for (i=1;i<=n;i++) 68 if (!((s[i]-‘0‘)%p)) 69 ss[i]=ss[i-1]+1,ls[i]=ls[i-1]+i; 70 else ss[i]=ss[i-1],ls[i]=ls[i-1]; 71 for (i=1;i<=m;i++) 72 { 73 scanf("%lld%lld",&l,&r); 74 printf("%lld\n",ls[r]-ls[l-1]-(ss[r]-ss[l-1])*(l-1)); 75 } 76 } 77 }
以上是关于[HNOI2016]大数的主要内容,如果未能解决你的问题,请参考以下文章