AC通道:http://www.lydsy.com/JudgeOnline/problem.php?id=4542
【题解】
把n个后缀组成的数字全部对p取模。
若s[l] ~ s[n]的余数和s[r] ~ s[n]的余数相同,那么s[l] ~ s[r - 1]区间内的数字就是p的倍数(l < r)
证明:设k为s[r-1]%p,x=r-l,n为s[l] ~ s[r - 1]区间内的数字,k%p=a
则(k+n*10^x)%p=a,若gcd(10^x,p)=1,因为k%p=a,所以n%p=0
由上面的证明过程可以知道当p=2或5时不成立,我们需要特判一下:
当p=2或5时,用b[i]记录在i及左边满足(s[i]-'0')%p=0的数的个数,c[i]记录i及左边的答案。
那么对于询问[l,r]的答案就是(c[r]-c[l-1])-(b[r]-b[l-1])*(l-1),这个动手推一下就出来了。
然后回到p不是2或5的情况:
很显然,这是一个经典的问题:在[l,r+1]内有多少对相同的数。
另外,注意离散化的使用。
/*************
bzoj 4542
by chty
2016.11.17
*************/
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<ctime>
#include<cmath>
#include<algorithm>
#include<map>
using namespace std;
typedef long long ll;
#define FILE "read"
#define MAXN 100010
#define up(i,j,n) for(ll i=j;i<=n;i++)
#define down(i,j,n) for(ll i=j;i>=n;i--)
struct node{ll x,y,id;}q[MAXN];
ll p,n,m,now,block,ans[MAXN],a[MAXN],num[MAXN],b[MAXN],c[MAXN];
char ch[MAXN];
map<ll,ll>Map;
namespace Init{
char buf[1<<15],*fs,*ft;
inline char getc() {return (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),fs==ft))?0:*fs++;}
inline ll read(){
ll x=0,f=1; char ch=getchar();
while(!isdigit(ch)) {if(ch=='-') f=-1; ch=getchar();}
while(isdigit(ch)) {x=x*10+ch-'0'; ch=getchar();}
return x*f;
}
}
namespace Mo_Team{
ll cnt[MAXN];
bool cmp(node a,node b) {return a.x/block==b.x/block?a.y<b.y:a.x/block<b.x/block;}
void add(ll x) {now+=cnt[x]; cnt[x]++;}
void del(ll x) {cnt[x]--; now-=cnt[x];}
void work(){
block=(ll)sqrt(n*1.0); sort(q+1,q+m+1,cmp);
up(i,1,m) q[i].y++;
ll l=1,r=0;
up(i,1,m){
while(q[i].x>l) del(a[l++]);
while(q[i].x<l) add(a[--l]);
while(q[i].y>r) add(a[++r]);
while(q[i].y<r) del(a[r--]);
ans[q[i].id]=now;
}
up(i,1,m) printf("%lld\n",ans[i]);
}
}
void init(){
p=Init::read();
scanf("%s",ch+1);
m=Init::read(); n=strlen(ch+1);
up(i,1,m){q[i].x=Init::read(); q[i].y=Init::read(); q[i].id=i;}
ll mul=1;
down(i,n,1){
mul=mul*10%p;
a[i]=(a[i+1]+(ch[i]-'0')*mul)%p;
num[i]=a[i];
}
sort(num+1,num+n+1);
up(i,1,n+1) Map[num[i]]=i;
up(i,1,n+1) a[i]=Map[a[i]];
}
void solve(){
if(p==2||p==5){
up(i,1,n) if((ch[i]-'0')%p==0) {b[i]=b[i-1]+1; c[i]=c[i-1]+i;}
else {b[i]=b[i-1]; c[i]=c[i-1];}
up(i,1,m) {ll l=q[i].x,r=q[i].y; printf("%lld\n",c[r]-c[l-1]-(b[r]-b[l-1])*(l-1));}
}
else Mo_Team::work();
}
int main(){
freopen(FILE".in","r",stdin);
freopen(FILE".out","w",stdout);
init();
solve();
return 0;
}