zoukankan      html  css  js  c++  java
  • 【洛谷P5072】盼君勿忘

    题目

    题目链接:https://www.luogu.com.cn/problem/P5072
    珂朵莉给了你一个序列,每次查询一个区间 \([l,r]\) 中所有子序列分别去重后的和 \(\bmod\ p\)

    思路

    第一道 Ynoi 黑 /fad。
    考虑每一个数在区间 \([l,r]\) 中的贡献。假设这个数字出现了 \(k\) 次,那么贡献为 \(2^{r-l+1}-2^{r-l+1-k}\)
    那么记 \(cnt[i]\) 表示数字 \(i\) 出现的次数,记 \(sum[i]\) 表示出现次数为 \(i\) 的数的和,那么每次询问答案即为

    \[\sum^{n}_{i=1}sum[i]\times (2^{r-l+1}-2^{r-l+1-i}) \]

    莫队乱搞即可。时间复杂度 \(O(nm+m\sqrt{n})\)。显然不够优秀。
    发现出现次数超过 \(\sqrt{n}\) 的数字不会超过 \(\sqrt{n}\) 个,所以可以用一个 \(\operatorname{unordered\_set}\) 记录出现次数超过 \(\sqrt{n}\) 的数字。
    然后每次询问枚举出现次数时只需要枚举到 \(\sqrt{n}\)。剩余不超过 \(\sqrt{n}\) 个数字直接算即可。
    但是每一次询问的模数不一样,如果对于每一个 \(2^i\) 都计算一次时间复杂度会乘上一个 \(\log n\)。所以我们可以每次询问与处理出 \(2^{i}(0\leq i<T)\)\(2^j(T|j)\)。然后每一个 \(2^k\) 都可以 \(O(1)\) 表示出来了。
    时间复杂度 \(O(m\sqrt{n})\)

    代码

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    
    const int N=100010,T=320;
    int n,Q,a[N],cnt[N];
    ll ans[N],power[2][T],sum[T];
    unordered_set<ll> s;
    
    struct Query
    {
    	int l,r,p,id,bel;
    	
    	friend bool operator <(Query x,Query y)
    	{
    		return (x.bel==y.bel)?(x.r<y.r):(x.bel<y.bel);
    	}
    }ask[N];
    
    int read()
    {
    	int d=0; char ch=getchar();
    	while (!isdigit(ch)) ch=getchar();
    	while (isdigit(ch)) d=(d<<3)+(d<<1)+ch-48,ch=getchar();
    	return d;
    }
    
    void ins(int x)
    {
    	if (cnt[x]<T) sum[cnt[x]]-=x;
    	cnt[x]++;
    	if (cnt[x]==T) s.insert(x);
    	if (cnt[x]<T) sum[cnt[x]]+=x;
    }
    
    void del(int x)
    {
    	if (cnt[x]<T) sum[cnt[x]]-=x;
    	if (cnt[x]==T) s.erase(s.find(x));
    	cnt[x]--;
    	if (cnt[x]<T) sum[cnt[x]]+=x;
    }
    
    int main()
    {
    	n=read(); Q=read();
    	for (int i=1;i<=n;i++)
    		a[i]=read();
    	int WYCtxdy=sqrt(n);
    	for (int i=1;i<=Q;i++)
    	{
    		ask[i]=(Query){read(),read(),read(),i,114514};
    		ask[i].bel=ask[i].l/WYCtxdy;
    	}
    	sort(ask+1,ask+1+Q);
    	for (int i=1,l=1,r=0;i<=Q;i++)
    	{
    		ll MOD=ask[i].p;
    		for (;l>ask[i].l;l--) ins(a[l-1]);
    		for (;r<ask[i].r;r++) ins(a[r+1]);
    		for (;l<ask[i].l;l++) del(a[l]);
    		for (;r>ask[i].r;r--) del(a[r]);
    		
    		power[0][0]=power[1][0]=1%MOD;
    		for (int j=1;j<T;j++) power[0][j]=power[0][j-1]*2LL%MOD;
    		power[1][1]=power[0][T-1]*2LL%MOD;
    		for (int j=2;j<T;j++) power[1][j]=power[1][j-1]*power[1][1]%MOD;
    		
    		int p1=(r-l+1)/T,p2=(r-l+1)%T,id=ask[i].id;
    		for (int j=1;j<T;j++)
    		{
    			int q1=(r-l+1-j)/T,q2=(r-l+1-j)%T;
    			ans[id]=(ans[id]+sum[j]%MOD*((power[1][p1]*power[0][p2]-power[1][q1]*power[0][q2])%MOD))%MOD;
    		}
    		for (unordered_set<ll>::iterator it=s.begin();it!=s.end();it++)
    		{
    			int q1=(r-l+1-cnt[*it])/T,q2=(r-l+1-cnt[*it])%T;
    			ans[id]=(ans[id]+*it*((power[1][p1]*power[0][p2]-power[1][q1]*power[0][q2])%MOD))%MOD;
    		}
    		ans[id]=(ans[id]+MOD)%MOD;
    	}
    	for (int i=1;i<=Q;i++)
    		printf("%lld\n",ans[i]);
    	return 0;
    }
    
  • 相关阅读:
    帕累托分布(Pareto distributions)、马太效应
    Generalized normal distribution and Skew normal distribution
    Secondary NameNode 的作用
    127.0.0.1和0.0.0.0地址的区别
    50070只有本机可以访问(除本机外无法访问)
    SecureCRT SSH 语法高亮
    深入理解VMware虚拟机网络通信原理
    CentOS Virtual Machine 设置SSH主机登录
    路由器(交换机)的光口和电口
    ECC校验
  • 原文地址:https://www.cnblogs.com/stoorz/p/13716646.html
Copyright © 2011-2022 走看看