P5072 [Ynoi Easy Round 2015] 盼君勿忘 题解

前言

  • 谁说的不卡常。。。

\(solve\)

  • 去重好难搞a,转化一下
  • 我们设序列长 \(k\),一个数 \(a\) 有 \(x\) 个,总共区间个数为 \(2^k\),那么不包含 \(a\) 的区间个数就有 \(2^{k-x}\),就是简单容斥
  • 我们开桶 \(col\) 维护一个数 \(i\) 出现的次数,用 \(s\) 维护出现次数为 \(i\) 的和,这样对于每一种出现次数贡献为 \(s_i*(2^{k}-2^{k-i})\)
  • 莫队统计 \(col\) 和 \(s\) 即可
  • 由于我们需要保证莫队的复杂度,所以统计 \(s\) 时需要以 \(o(1)\) 维护贡献,还要求方便遍历,即需要一个支持 \(O(1)\) 插入删除且遍历迅速的东西,双向链表,元素个数大概是 \(\sqrt n\) 的
  • 但是我们要计算 \(2\) 的 \(k\) 次方,带只老哥不太行,我们需要一个 \(O(1)\) 的算 \(2\) 的 \(k\) 次方的东西,光速幂
  • 光速幂就是提前处理出 \(2^0,2^1,\dots,2^{\sqrt n-1}\) 并处理出 \(2^{\sqrt n},\dots,2^{n}\),然后直接通过计算 \(O(1)\) 算
点击查看代码
namespace lightpower
{
    long long p1[maxn],p2[maxn];
    void ini(int p)
    {
        p1[0]=p2[0]=1;
        for (int i=1;i<=k+10;i++)
            p1[i]=(p1[i-1]<<1)%p;
        for (int i=1;i<=k+10;i++)
            p2[i]=p1[k]*p2[i-1]%p;
    }
    long long power(int x,int p) {return p1[x%k]*p2[x/k]%p;}
}using namespace lightpower;
  • 然后没了,就是卡常卡卡卡
点击查看代码
#pragma G++ optimize("O3,unroll-loops")
#include<bits/stdc++.h>
#define endl '\n'
using namespace std;
constexpr int maxn=1e5+10;
struct IO
{
	static const int Size=(1<<18);
	char buf[Size],*p1,*p2;
	int st[105],Top;
	~IO(){clear();}
	inline void clear(){fwrite(buf,1,Top,stdout);Top=0;}
	inline char gc(){return p1==p2&&(p2=(p1=buf)+fread(buf,1,Size,stdin),p1==p2)?EOF:*p1++;}
	inline void pc(const char c){Top==Size&&(clear(),0);buf[Top++]=c;}
	inline IO& operator >>(char& c){while(c=gc(),c==' ' || c=='\n' || c=='\r');return *this;}
	template<typename T>inline IO& operator >>(T& x)
    {
		x=0;bool f=0;char c=gc();
		while(!isdigit(c)){if(c=='-') f=1;c=gc();}
		while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=gc();}
		f?x=-x:0;
		return *this;
	}
	inline IO& operator >>(string& s)
    {
		s="";char c=gc();
		while(c==' ' || c=='\n' || c=='\r') c=gc();
		while(c!=' ' && c!='\n' && c!='\r' && c!=EOF) s+=c,c=gc();
		return *this;
	}
	inline IO& operator <<(const char c){pc(c);return *this;}
	template<typename T> inline IO& operator <<(T x)
    {
		if(x<0) pc('-'),x=-x;
		do st[++st[0]]=x%10,x/=10;while(x);
		while(st[0]) pc(st[st[0]--]+'0');
		return *this;
	}
	inline IO& operator <<(const string s){for(auto c:s) pc(c);return *this;}
	inline IO& operator <<(const char* c){for(int i=0;c[i];i++) pc(c[i]);return *this;}
}fin,fout;
int n,m;
int a[maxn];
int k;
namespace bidirectional_list
{
    int pre[maxn],nxt[maxn],tot;
    inline void Ins(int x) {nxt[tot]=x,pre[x]=tot,tot=x;}
    inline void Del(int x)
    {
        if (x == tot)
            nxt[pre[x]]=0,tot=pre[x];
        else
            nxt[pre[x]]=nxt[x],pre[nxt[x]]=pre[x];
        pre[x]=nxt[x]=0;
    }
}using namespace bidirectional_list;
int L[maxn],R[maxn],pos[maxn],cnt,B;
void init()
{
    B=sqrt(m)+1;
    cnt=n/B;
    for (int i=1;i<=cnt;i++)
        L[i]=R[i-1]+1,R[i]=B*i;
    if (R[cnt]<n)
        cnt++,L[cnt]=R[cnt-1]+1,R[cnt]=n;
    for (int i=1;i<=cnt;i++)
        for (int j=L[i];j<=R[i];j++)
            pos[j]=i;
}
struct _ {int l,r,p,id;}q[maxn];
long long col[maxn],s[maxn];
inline void add(int x)
{
    s[col[x]]-=x;
    if (!s[col[x]])
        Del(col[x]);
    col[x]++;
    if (!s[col[x]])
        Ins(col[x]);
    s[col[x]]+=x;
}
inline void del(int x)
{
    s[col[x]]-=x;
    if (!s[col[x]])
        Del(col[x]);
    col[x]--;
    if (!s[col[x]])
        Ins(col[x]);
    s[col[x]]+=x;
}
int ans[maxn];
namespace lightpower
{
    long long p1[maxn],p2[maxn];
    void ini(int p)
    {
        p1[0]=p2[0]=1;
        for (int i=1;i<=k+10;i++)
            p1[i]=(p1[i-1]<<1)%p;
        for (int i=1;i<=k+10;i++)
            p2[i]=p1[k]*p2[i-1]%p;
    }
    long long power(int x,int p) {return p1[x%k]*p2[x/k]%p;}
}using namespace lightpower;
signed main()
{
    fin >> n >> m;
    k=sqrt(n);
    for (int i=1;i<=n;i++)
        fin >> a[i];
    init();
    for (int i=1;i<=m;i++)
    {
        int l,r,p;
        fin >> l >> r >> p;
        q[i]={l,r,p,i};
    }
    sort(q+1,q+1+m,[](_ a,_ b)
    {
        return pos[a.l] == pos[b.l] ? 
        (pos[a.l]&1) ? a.r<b.r : a.r>b.r :
        pos[a.l]<pos[b.l];
    });
    int l=1,r=0;
    for (int i=1;i<=m;i++)
    {
        const int ll=q[i].l,rr=q[i].r,p=q[i].p,id=q[i].id;
        ini(p);
        while (l>ll) add(a[--l]);
        while (r<rr) add(a[++r]);
        while (l<ll) del(a[l++]);
        while (r>rr) del(a[r--]);
        for (int j=nxt[0];j;j=nxt[j])
            (ans[id]+=(s[j]*(power(rr-ll+1,p)%p-power(rr-ll+1-j,p)+p))%p)%=p;
    }
    for (int i=1;i<=m;i++)
        fout << ans[i] << endl;
    return 0;
}
posted @ 2026-09-30 08:11  msjing  阅读(10)  评论(2)    收藏  举报