zoukankan      html  css  js  c++  java
  • Luogu 3245 大数

    Luogu 3245 大数

    • 开始就想 (10) 进制 (hash) ,(Hash(r)equiv Hash(l-1)cdot 10^{r-l+1}) ,感觉没什么美妙的性质啊...
    • 然后把 (hash) 换个方向,先加低位,再加高位,就成了 (frac {Hash(l)-Hash(r+1)} {10^{n-r}}equiv 0) ,似乎,就很美妙了?
    • (P ot=2,5) 时,下面的分母有逆元,那么只能是 (Hash(l)equiv Hash(r+1)) ,就变成了在一段区间内问相同元素的对数,离散化之后,用莫队可以解决.
    • (P=2,5) 时,一段区间内仅有以 (P,0) 结尾的串符合条件,计数相当简单.
    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    inline int read()
    {
    	int out=0,fh=1;
    	char jp=getchar();
    	while ((jp>'9'||jp<'0')&&jp!='-')
    		jp=getchar();
    	if (jp=='-')
    		fh=-1,jp=getchar();
    	while (jp>='0'&&jp<='9')
    		out=out*10+jp-'0',jp=getchar();
    	return out*fh;
    }
    const int MAXN=1e5+10;
    int n,m,P;
    inline int add(int a,int b)
    {
    	return (a + b) % P;
    }
    inline int mul(int a,int b)
    {
    	return 1LL * a * b % P;
    }
    struct query
    {
    	int l,r,id,bel;
    	bool operator < (const query &rhs) const
    	{
    		if(bel!=rhs.bel)
    			return bel<rhs.bel;
    		if(r!=rhs.r)
    			return r<rhs.r;
    		return l<rhs.l;
    	}
    }q[MAXN];
    char buf[MAXN];
    int Hash[MAXN],cp[MAXN];
    int cnt[MAXN];
    ll ans[MAXN],res;
    void add(int x)
    {
    	res+=cnt[Hash[x]];
    	++cnt[Hash[x]];
    }
    void rem(int x)
    {
    	--cnt[Hash[x]];
    	res-=cnt[Hash[x]];
    }
    int sumcnt[MAXN],sumpos[MAXN];
    void solve_spj()
    {
    	for(int i=1;i<=n;++i)
    	{
    		if(buf[i]-'0'==0 || buf[i]-'0'==P)
    			sumcnt[i]=1,sumpos[i]=i;
    		sumcnt[i]+=sumcnt[i-1];
    		sumpos[i]+=sumpos[i-1];
    	}
    	m=read();
    	for(int i=1;i<=m;++i)
    	{
    		int l=read(),r=read();
    		ll cntsum=sumcnt[r]-sumcnt[l-1],possum=sumpos[r]-sumpos[l-1];
    		ll res=possum-1LL*(l-1)*cntsum;
    		printf("%lld
    ",res);
    	}
    }
    int main()
    {
    	P=read();
    	scanf("%s",buf+1);
    	n=strlen(buf+1);
    	if(P==2 || P==5)
    	{
    		solve_spj();
    		return 0;
    	}
    	int pow10=1;
    	for(int i=n;i>=1;--i)
    	{
    		cp[i]=Hash[i]=add(Hash[i+1],mul(buf[i]-'0',pow10));
    		pow10=mul(pow10,10);
    	}
    	++n;//0
    	sort(cp+1,cp+1+n);
    	int tot=unique(cp+1,cp+1+n)-cp-1;
    	for(int i=1;i<=n;++i)
    		Hash[i]=lower_bound(cp+1,cp+1+tot,Hash[i])-cp;
    	m=read();
    	int BlockSize=sqrt(m);
    	for(int i=1;i<=m;++i)
    	{
    		q[i].l=read();
    		q[i].r=read();
    		q[i].id=i;
    		q[i].bel=q[i].l/BlockSize;
    	}
    	sort(q+1,q+1+m);
    	int L=1,R=0;
    	for(int i=1;i<=m;++i)
    	{
    		int l=q[i].l,r=q[i].r;
    		++r;
    		if(l==r)
    			continue;
    		while(R<r)
    			add(++R);
    		while(L<l)
    			rem(L++);
    		while(L>l)
    			add(--L);
    		while(R>r)
    			rem(R--);
    		ans[q[i].id]=res;
    	}
    	for(int i=1;i<=m;++i)
    		printf("%lld
    ",ans[i]);
    	return 0;
    }
    
  • 相关阅读:
    计算机操作系统之进程管理
    剑指offer——两个链表的第一个公共结点
    剑指offer——数字在排序数组中出现的次数
    剑指offer——二叉树的深度与平衡二叉树的判断
    剑指offer——数组中只出现一次的数字
    剑指offer——和为s的两个数字VS和为s的连续正数序列
    剑指offer——翻转单词顺序VS左旋转字符串
    剑指offer——扑克牌的顺子
    剑指offer——圆圈中最后剩下的数字
    剑指offer——求1+2+...+n
  • 原文地址:https://www.cnblogs.com/jklover/p/10685841.html
Copyright © 2011-2022 走看看