zoukankan      html  css  js  c++  java
  • 【BZOJ4542】[Hnoi2016]大数 莫队

    【BZOJ4542】[Hnoi2016]大数

    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]为 213。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。

    题解:看到题容易想到用莫队。用sum[i]表示S的前i位组成的数%P的值,那么如果i...j能组成一个%P=0的数,意味着

    $sum[j]-sum[i]*10^{j-i}=0(mod P) ightarrow sum[j]*10^{-j}=sum[i]*10^{-i} (mod P)$

    所以离散化一下,然后就变成了问一个区间中有多少对相同数,的用桶+莫队即可。

    注意特判P=2,P=5的情况!因为上式不再成立!具体方法是直接判断哪些串的末尾的数能被2和5整除即可。

     

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    #include <cmath>
    using namespace std;
    typedef long long ll;
    const int maxn=100010;
    int B,P,n,m,nm;
    char str[maxn];
    int v[maxn],s[maxn];
    ll sum,ans[maxn];
    ll s1[maxn],s2[maxn];
    struct node
    {
    	int val,org;
    }p[maxn];
    struct query
    {
    	int l,r,org;
    }q[maxn];
    bool cmpp(node a,node b)
    {
    	return a.val<b.val;
    }
    bool cmpq(query a,query b)
    {
    	return (a.l/B==b.l/B)?(a.r<b.r):(a.l/B<b.l/B);
    }
    int main()
    {
    	scanf("%d%s%d",&P,str,&m),n=strlen(str);
    	int i,l,r;
    	if(P==2||P==5)
    	{
    		for(i=1;i<=n;i++)
    		{
    			s1[i]=s1[i-1],s2[i]=s2[i-1];
    			if((str[i-1]-'0')%P==0)	s1[i]+=i,s2[i]++;
    		}
    		for(i=1;i<=m;i++)
    		{
    			scanf("%d%d",&l,&r);
    			printf("%lld
    ",s1[r]-s1[l-1]-(l-1)*(s2[r]-s2[l-1]));
    		}
    		return 0;
    	}
    	p[0].val=0;
    	for(i=1;i<=n;i++)	p[i].val=(10ll*p[i-1].val+str[i-1]-'0')%P,p[i].org=i;
    	ll tmp=1;
    	for(i=n;i>=1;i--,tmp=tmp*10%P)	p[i].val=tmp*p[i].val%P;
    	sort(p,p+n+1,cmpp);
    	for(i=0;i<=n;i++)
    	{
    		if(!i||p[i].val>p[i-1].val)	nm++;
    		v[p[i].org]=nm;
    	}
    	B=int(sqrt(double(n)));
    	for(i=1;i<=m;i++)	scanf("%d%d",&q[i].l,&q[i].r),q[i].l--,q[i].org=i;
    	sort(q+1,q+m+1,cmpq);
    	l=1,r=0;
    	for(i=1;i<=m;i++)
    	{
    		while(l>q[i].l)	l--,sum+=s[v[l]],s[v[l]]++;
    		while(l<q[i].l)	s[v[l]]--,sum-=s[v[l]],l++;
    		while(r<q[i].r)	r++,sum+=s[v[r]],s[v[r]]++;
    		while(r>q[i].r)	s[v[r]]--,sum-=s[v[r]],r--;
    		ans[q[i].org]=sum;
    	}
    	for(i=1;i<=m;i++)	printf("%lld
    ",ans[i]);
    	return 0;
    }

     

  • 相关阅读:
    Vue自带的过滤器
    Spring Boot定时任务应用实践
    iOS中NSDate常用转换操作整合
    iOS中NSFileManager文件常用操作整合
    定位城市的封装
    微信支付和支付宝的封装
    App审核被拒(后台定位被拒,ipv6被拒,广告标示被拒的解决方案)
    按钮图片文字随意摆放
    设备信息大全
    Library not found for -lAPOpenSdk
  • 原文地址:https://www.cnblogs.com/CQzhangyu/p/7468853.html
Copyright © 2011-2022 走看看