• [bzoj4542][Hnoi2016]大数——同余+莫队


    题目大意:

    给定一个质数p和一串数字序列,每次询问一个区间[L,R]中有多少个子区间表示的数为p的倍数。

    思路:

    首先考虑如何判断一段数字是不是p的倍数,不难想到可以用模p意义下的值来判断,但是这样最多便有可能会有(n^2)个余数,每一次计算也需要区间长度的时间,不太方便。
    考虑记录以每一个点为起点的后缀所表示的数字在模p下的结果(sum_i),对于任意一段区间[L,R],不难发现(sum_l-sum_{r+1})所表示的是[L,R]所表示的数( imes 10^x),对于素数里面只有2,5是有可能整除后面的(10^x),于是我们只需要对2,5特殊判断一下,其他的素数直接用(sum_l-sum_{r+1})对于p取模的结果来判断就好了。
    这样对于任意一个区间[L,R],我们只需要看(sum_l)(sum_{r+1})是否相同,题目便转化为了数一个区间内的相同颜色的个数并求其贡献,这种模型直接用莫队维护即可。

    #include<bits/stdc++.h>
    
    #define REP(i,a,b) for(int i=a,i##_end_=b;i<=i##_end_;++i)
    #define DREP(i,a,b) for(int i=a,i##_end_=b;i>=i##_end_;--i)
    #define MREP(i,x) for(int i=beg[x],v;v=to[i],i;i=las[i])
    #define debug(x) cout<<#x<<"="<<x<<endl
    #define fi first
    #define se second
    #define mk make_pair
    #define pb push_back
    typedef long long ll;
    
    using namespace std;
    
    void File(){
    	freopen("bzoj4542.in","r",stdin);
    	freopen("bzoj4542.out","w",stdout);
    }
    
    template<typename T>void read(T &_){
    	T __=0,mul=1; char ch=getchar();
    	while(!isdigit(ch)){
    		if(ch=='-')mul=-1;
    		ch=getchar();
    	}
    	while(isdigit(ch))__=(__<<1)+(__<<3)+(ch^'0'),ch=getchar();
    	_=__*mul;
    }
    
    const int maxn=1e5+10;
    int n,p,m,a[maxn];
    char str[maxn];
    
    namespace subtask1{
    	ll s1[maxn],s2[maxn];
    	void work(){
    		REP(i,1,n){
    			s1[i]+=s1[i-1];
    			s2[i]+=s2[i-1];
    			if(a[i]%p==0){
    				++s1[i];
    				s2[i]+=i;
    			}
    		}
    		int l,r;
    		REP(i,1,m){
    			read(l),read(r);
    			printf("%lld
    ",s2[r]-s2[l-1]-(s1[r]-s1[l-1])*(l-1));
    		}
    	}
    }
    
    namespace subtask2{
    	int tot,bel[maxn];
    	ll sum[maxn],p10[maxn],b[maxn],ans[maxn],ton[maxn],now;
    	struct Query{
    		int l,r,id;
    		bool operator < (const Query & tt) const {
    			if(bel[l]==bel[tt.l])return r<tt.r;
    			return bel[l]<bel[tt.l];
    		}
    	}qu[maxn];
    	void calc(int pos,int ty){
    		int w=sum[pos];
    		now-=ton[w]*(ton[w]-1)/2;
    		ton[w]+=ty;
    		now+=ton[w]*(ton[w]-1)/2;
    	}
    	void work(){
    		p10[0]=1;
    		REP(i,1,n)p10[i]=p10[i-1]*10%p;
    		ll ss=0;
    		DREP(i,n,1){
    			ss=(ss+a[i]*p10[n-i])%p;
    			sum[i]=(ss+p)%p;
    		}
    
    		REP(i,1,n+1)b[++tot]=sum[i];
    		sort(b+1,b+tot+1);
    		tot=unique(b+1,b+tot+1)-b-1;
    		REP(i,1,n+1)sum[i]=lower_bound(b+1,b+tot+1,sum[i])-b;
    
    		REP(i,1,n)bel[i]=(i-1)/400+1;
    		REP(i,1,m)read(qu[i].l),read(qu[i].r),qu[i].id=i;
    		sort(qu+1,qu+m+1);
    
    		int L=1,R=0;
    		REP(i,1,m){
    			int l=qu[i].l,r=qu[i].r;
    			while(L>l)calc(L-1,1),--L;
    			while(R<r+1)calc(R+1,1),++R;
    			while(L<l)calc(L,-1),++L;
    			while(R>r+1)calc(R,-1),--R;
    			ans[qu[i].id]=now;
    		}
    		REP(i,1,m)printf("%lld
    ",ans[i]);
    	}
    }
    
    int main(){
    	File();
    	read(p);
    	scanf("%s",str+1);
    	n=strlen(str+1);
    	REP(i,1,n)a[i]=str[i]^'0';
    	read(m);
    	if(p==2 || p==5)return subtask1::work(),0;
    	else return subtask2::work(),0;
    	return 0;
    }
    
    
  • 相关阅读:
    今天,我们来聊一聊互联网真的有你所期待的那么好吗?来自一个老码农的碎碎念
    新鲜出炉!阿里Java后端面经,已拿offer!
    面试阿里,字节跳动,美团必被问到的红黑树原来这么简单
    凭借着这份Spring面试题,我拿到了阿里,字节跳动美团的offer!
    深度分析:理解Java中的多态机制,一篇直接帮你掌握!
    gdb调试core dump使用
    665. Non-decreasing Array
    netstat命令详解
    ifconfig命令
    #paragma详解
  • 原文地址:https://www.cnblogs.com/ylsoi/p/10073511.html
Copyright © 2020-2023  润新知