zoukankan      html  css  js  c++  java
  • BZOJ 4542: [Hnoi2016]大数

    4542: [Hnoi2016]大数

    Time Limit: 20 Sec  Memory Limit: 128 MB
    Submit: 1354  Solved: 470
    [Submit][Status][Discuss]

    Description

      小 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的倍数。

    Input

      第一行一个整数:P。第二行一个串:S。第三行一个整数:M。接下来M行,每行两个整数 fr,to,表示对S 的
    子串S[fr…to]的一次询问。注意:S的最左端的数字的位置序号为 1;例如S为213567,则S[1]为 2,S[1…3]为 2
    13。N,M<=100000,P为素数

    Output

      输出M行,每行一个整数,第 i行是第 i个询问的答案。

    Sample Input

    11
    121121
    3
    1 6
    1 5
    1 4

    Sample Output

    5
    3
    2
    //第一个询问问的是整个串,满足条件的子串分别有:121121,2112,11,121,121。

    HINT

     2016.4.19新加数据一组

    Source

    分析:

    考虑如果一个子串如果能够被$p$整除,就代表$s[l,r]%p==0$,这是区间的形式,那么考虑转化成后缀的形式:$s[l]%p-s[r+1]%p==0$,也就是说$s[l]%p==s[r+1]%p$,诶,忽然发现这是经典的莫队问题...询问区间内相等的数对个数...

    但是这个方法不适用于$2$和$5$,因为就算是$s[l]%p!=s[r+1]$子串也有可能合法,并且这两个数只需要判断最后一位就好,所以前缀和维护...

    代码:

    #include<algorithm>
    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<cmath>
    //by NeighThorn
    using namespace std;
    
    const int maxn=100000+5;
    
    int n,m,p,blo,len,id[maxn],cnt[maxn];
    long long tmp,no[maxn],mp[maxn],ans[maxn],sum[maxn],power[maxn];
    
    char s[maxn];
    
    struct M{
    	int l,r,num;
    	friend bool operator < (M a,M b){
    		if(id[a.l]!=id[b.l])
    			return id[a.l]<id[b.l];
    		return a.r<b.r;
    	}
    }q[maxn];
    
    inline int read(void){
    	char ch=getchar();int x=0;
    	while(!(ch>='0'&&ch<='9')) ch=getchar();
    	while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
    	return x;
    }
    
    inline void change(int x,int val){
    	x=no[x];
    	if(cnt[x]>1) tmp-=1LL*cnt[x]*(cnt[x]-1)/2;
    	cnt[x]+=val;
    	if(cnt[x]>1) tmp+=1LL*cnt[x]*(cnt[x]-1)/2;
    }
    
    inline int check(char a){
    	int x=a-'0';
    	if(p==2){
    		if(x&1) return 0;
    		return 1;
    	}
    	else if(p==5){
    		if(x==0||x==5) return 1;
    		return 0;
    	}
    }
    
    inline void solve1(void){
    	for(int i=1;i<=n;i++)
    		sum[i]=sum[i-1]+check(s[i])*i,no[i]=no[i-1]+check(s[i]);
    	for(int i=1,l,r;i<=m;i++)
    		l=read(),r=read(),printf("%lld
    ",sum[r]-sum[l-1]-1LL*(no[r]-no[l-1])*(l-1));
    }
    
    signed main(void){
    #ifndef ONLINE_JUDGE
    	freopen("in.txt","r",stdin);
    	freopen("out.txt","w",stdout);
    #endif
    	p=read(),scanf("%s",s+1),m=read(),n=strlen(s+1);blo=sqrt(n);
    	if(p==2||p==5) return solve1(),0;
    	for(int i=1;i<=n;i++) id[i]=(i-1)/blo+1;power[n]=1;
    	for(int i=1;i<=m;i++) q[i].l=read(),q[i].r=read()+1,q[i].num=i;
    	for(int i=n-1;i>=1;i--) power[i]=1LL*power[i+1]*10%p;
    	for(int i=n;i>=1;i--)
    		no[i]=(no[i+1]+1LL*power[i]*(s[i]-'0')%p)%p,mp[i]=no[i];mp[n+1]=0;
    	sort(mp+1,mp+1+n+1);len=unique(mp+1,mp+n+1+1)-mp-1;sort(q+1,q+m+1);
    	for(int i=1;i<=n+1;i++) no[i]=lower_bound(mp+1,mp+len+1,no[i])-mp;
    	for(int i=1,l=1,r=0;i<=m;i++){
    		for(;l<q[i].l;l++) change(l  ,-1);
    		for(;l>q[i].l;l--) change(l-1, 1);
    		for(;r<q[i].r;r++) change(r+1, 1);
    		for(;r>q[i].r;r--) change(r  ,-1);
    		ans[q[i].num]=tmp;
    	}
    	for(int i=1;i<=m;i++)
    		printf("%lld
    ",ans[i]);
    	return 0;
    }
    

    By NeighThorn

  • 相关阅读:
    TextEdit 使用Mask验证输入格式为邮箱
    大牛博客收藏
    WPF的Dispatcher类里的BeginInvoke,Invoke,InvokeAsync
    DispatcherPriority 枚举
    WPF 线程处理
    Winform UI线程和处理线程交互(进度更新显示)
    C# DataTable 类使用
    string.Format对C#字符串格式化
    C# 线程学习记录
    WPF 控件库
  • 原文地址:https://www.cnblogs.com/neighthorn/p/6613522.html
Copyright © 2011-2022 走看看