您的位置:首页 > 其它

[BZOJ4542]大数

2016-04-19 21:07 357 查看
如何判断一个炒鸡大的数$n$能不能被另一个数$P$整除,,,我们有如下结论若$xmodP=a$,且$(n*10^{k}+x)modP=a$,$k$为$x$的长度,$gcd(P,10^{k})=1$那么$nmodP=0$

胡乱证明分割线**********

因为$(n*10^{k}+x)modP=((n*10^{k})modP+xmodP)modP=a$,且$xmodP=a$,则$(n*10^{k})modP=0$

当且仅当$10^{k}modP$不为$0$时$nmodP=0$

当满足这个条件时,我们把$x$看作序列的后缀$P$,问题就转化为求区间$[l,r+1]$中,有多少对$a$相同,,,莫队again

由于$P$是质数,,,所以需要特判的只有$2$和$5$

所谓的特判就是数一哈有几个偶数,几个$0$或$5$什么的,,,

爸在嚄见新机表

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define maxn 100005
struct node{ int l,r,blc,id; ll ans; }q[maxn];
char s[maxn];
int n,m,hh,cnt[maxn];
ll P,tong[maxn],A[maxn],hsh[maxn],pre[maxn];
bool cmp1(node a,node b){
if(a.blc!=b.blc)return a.blc<b.blc;
else if(a.r!=b.r)return a.r<b.r;
else return a.l<b.l;
}
bool cmp2(node a,node b){ return a.id<b.id; }
void PP(){
s[++n]='0';
ll mi=1;
for(int i=n;i;i--){
hsh[++hh]=A[i]=((s[i]-'0')*mi%P+A[i+1]%P)%P;
mi=mi*10%P;
}
sort(hsh+1,hsh+1+hh);
hh=unique(hsh+1,hsh+1+hh)-(hsh+1);
for(int i=1;i<=n;i++)
A[i]=lower_bound(hsh+1,hsh+1+hh,A[i])-hsh;
}
void MD(){
sort(q+1,q+1+m,cmp1);
int l=1,r=0;
ll ans=0;
for(int i=1;i<=m;i++){
while(r<q[i].r)ans+=tong[A[++r]]++;
while(r>q[i].r)ans-=--tong[A[r--]];
while(l>q[i].l)ans+=tong[A[--l]]++;
while(l<q[i].l)ans-=--tong[A[l++]];
q[i].ans=ans;
}
sort(q+1,q+1+m,cmp2);
for(int i=1;i<=m;i++)
printf("%lld\n",q[i].ans);
}
void solve1(){
PP();
int block=sqrt(n);
scanf("%d",&m);
for(int i=1;i<=m;i++){
scanf("%d%d",&q[i].l,&q[i].r);
q[i].r++,q[i].id=i;
q[i].blc=(q[i].l-1)/block+1;
}
MD();
}
void solve2(){
for(int i=1;i<=n;i++){
pre[i]=pre[i-1];
cnt[i]=cnt[i-1];
if((P==2&&(s[i]-'0')%2==0)||(P==5&&(s[i]-'0'==0||s[i]-'0'==5)))
pre[i]+=i,cnt[i]++;
}
scanf("%d",&m);
int l,r;
for(int i=1;i<=m;i++){
scanf("%d%d",&l,&r);
printf("%lld\n",pre[r]-pre[l-1]-(cnt[r]-cnt[l-1])*(l-1));
}
}
int main(){
scanf("%lld%s",&P,s+1);
n=strlen(s+1);
if(P!=2&&P!=5)solve1();
else solve2();
return 0;
}


View Code
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: