bzoj4542: [Hnoi2016]大数(莫队)

  这题...离散化...$N$和$n$搞错了...查了$2h$...QAQ

  考虑$s[l...r]$,可以由两个后缀$suf[l]-suf[r+1]$得到$s[l...r]$代表的数乘$10^k$得到的结果,如果$p$不为$2$或$5$,即$gcd(p, 10^k)=1$,那么显然$s[l...r]$乘$10^k$模$p$为$0$的话,$s[l...r]$模p也为$0$,所以我们就可以变成询问$[l,r+1]$里有几个相同的后缀了。

  如果$p$为$2$或$5$的话,我们还得判断这个数的个位是否是$2$或$5$的倍数。

#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<algorithm>
#define ll long long
using namespace std;
const int maxn=, inf=1e9;
struct poi{int l, r, pos;}q[maxn];
int n, N, m, blo;
int bl[maxn], cnt[maxn], cnt2[maxn], b[maxn], sum[maxn];
ll p, ANS;
ll ans[maxn], mi[maxn];
char s[maxn];
inline void read(int &k)
{
int f=; k=; char c=getchar();
while(c<'' || c>'') c=='-'&&(f=-), c=getchar();
while(c<='' && c>='') k=k*+c-'', c=getchar();
k*=f;
}
bool operator < (poi a, poi b)
{return bl[a.l]<bl[b.l] || (bl[a.l]==bl[b.l] && ((bl[a.l]&)?a.r<b.r:a.r>b.r));}
inline void update(int x, int delta, int ty)
{
if(delta==)
{
ANS+=(!ty || p> || (s[x-]-'')%p==)*delta*(ty?cnt[sum[x]]:cnt2[sum[x]]);
cnt[sum[x]]+=delta;
cnt2[sum[x]]+=(p> || (s[x-]-'')%p==)*delta;
}
else
{
cnt[sum[x]]+=delta;
cnt2[sum[x]]+=(p> || (s[x-]-'')%p==)*delta;
ANS+=(!ty || p> || (s[x-]-'')%p==)*delta*(ty?cnt[sum[x]]:cnt2[sum[x]]);
}
}
int main()
{
scanf("%lld", &p); scanf("%s", s+); n=strlen(s+);
blo=sqrt(n); for(int i=;i<=n;i++) bl[i]=(i-)/blo+;
mi[]=; for(int i=;i<=n;i++) mi[i]=mi[i-]*%p;
for(int i=n;i;i--) sum[i]=(sum[i+]+mi[n-i]*(s[i]-''))%p, b[i]=sum[i]; N=n; b[++N]=;
sort(b+, b++N); N=unique(b+, b++N)-b-;
for(int i=;i<=n+;i++) sum[i]=lower_bound(b+, b++N, sum[i])-b;
read(m);
for(int i=;i<=m;i++) read(q[i].l), read(q[i].r), q[i].r++, q[i].pos=i;
sort(q+, q++m);
for(int i=, l=, r=;i<=m;i++)
{
while(l<q[i].l) update(l++, -, );
while(l>q[i].l) update(--l, , );
while(r<q[i].r) update(++r, , );
while(r>q[i].r) update(r--, -, );
ans[q[i].pos]=ANS;
}
for(int i=;i<=m;i++) printf("%lld\n", ans[i]);
}
上一篇:Java笔记(十四)……抽象类与接口


下一篇:Java中instanceof与getClass的区别