[Ynoi2015]盼君勿忘

0|1题目传送门

第一道 Ynoi 纪念一下qwq

1|0题意

  • 给定一个序列,每次求一个区间 [l,r] 中所有子序列分别去重后的和 modp

2|0Sol

观察题意,可以发现:

  1. 可离线。

  2. 每次模数不同。

  3. 十有八九爆 int

对于第 1 点,容易想到用莫队解决问题。

那么时间复杂度已经到 O(nn) 了。(


我们考虑每一位对答案的贡献。

对于区间 [l,r],考虑 ai 的贡献 。(lir

ai 在区间 [l,r] 中出现 cntai 次。

我们知道,一个元素总数为 k 的集合的子集个数为 2k 个。

可由 i=1k(ki)=2k 得出结论。

那么我们接下来算单个元素贡献有两种推导方法。

2|1Sol 1

我们直接从选入手。

那么可得贡献即为选的乘上不选的状态数。

(2cntai1)×2rl+1cntai

其中 (2cntai1) 表示选的非空子集。

可化为 2rl+12rl+1cntai

2|2Sol 2

我们转换一下思路,一个子序列只有包含和不包含两种情况。

那么我们可以想到用总数减去不包含的状态数。

即直接可得 2rl+12rl+1cntai


我们考虑在莫队时保存出现次数相同元素的和。

需要快速插入,删除。

由于不需要保证有序,容易想到双向链表。(建议手写)

O(1) 时间完成插入删除操作。


我们考虑模数不同,如何迅速求出 2kmodp

我们考虑关于 n 分组。

2k=2kn×n+kmodn=2kn×n×2kmodn

那么我们可以预处理出 212223...2n22n23n...2n 取模后的值。

并用上面的公式计算。


那么,似乎问题解决完了?qaq

为了卡常,我们全写 int,想着还有取模呢。qaq

交一发样例,过了。交一发,WAWAWA,抱灵了。(((

这时候你需要在一些可能爆炸的地方强制类型转换成 long long。qwq

这样才可能不 WA。(

不要问我怎么知道 我调这个调了 6 天才发现。

那么交一发 A 了qwq。

为啥加了火车头比不加慢啊qaq

给个刚好能过的代码主要在#9被卡。(

/* *** 还要继续努力 成为一名烤咕学家哦 *** */ #include<bits/stdc++.h> #define re register int using namespace std; typedef long long ll; const int N=1e5+5; int n,m,a[N],len,ans[N],cnt[N],sum[N],l=1,r=0,pw1[N],pw2[N]; struct Question{int l,r,p,id,pos;}q[N]; struct LINKED_LIST{ struct Link{int pre,nxt;}lk[N];int cnt; LINKED_LIST(){cnt=0;} inline void Insert(int x){ lk[cnt].nxt=x; lk[x].pre=cnt; cnt=x; } inline void Erase(int x){ if(x^cnt){ lk[lk[x].pre].nxt=lk[x].nxt; lk[lk[x].nxt].pre=lk[x].pre; } else cnt=lk[x].pre; lk[x].pre=lk[x].nxt=0; } }qaq; template <typename T> inline void rd(T &x){ re fl=1;x=0;char c=getchar(); for(;!isdigit(c);c=getchar()) if(c=='-') fl=-fl; for(;isdigit(c);c=getchar()) x=(x<<3)+(x<<1)+c-'0'; x*=fl; } void wr(int x){ if(x<0) x=-x,putchar('-'); if(x<10) putchar(x+'0'); if(x>9) wr(x/10),putchar(x%10+'0'); } bool cmp(Question x,Question y){ if(x.pos!=y.pos) return x.pos<y.pos; if(x.pos&1) return x.r<y.r; return x.r>y.r; } inline void init_pow(int p){ pw1[0]=pw2[0]=1; for(re i=1;i<=len;i++) pw1[i]=((ll)1ll*pw1[i-1]*2)%p; for(re i=1;i<=len;i++) pw2[i]=((ll)1ll*pw2[i-1]*pw1[len])%p; } inline int get_pow(int x,int p){return ((ll)pw1[x%len]*pw2[x/len])%p;} inline void upd(int x,int op){ sum[cnt[a[x]]]-=a[x]; if(!sum[cnt[a[x]]]) qaq.Erase(cnt[a[x]]); cnt[a[x]]+=op; if(!sum[cnt[a[x]]]) qaq.Insert(cnt[a[x]]); sum[cnt[a[x]]]+=a[x]; } int main(){ // freopen(".in","r",stdin); // freopen(".out","w",stdout); rd(n);rd(m); len=(int)sqrt(n); for(re i=1;i<=n;i++) rd(a[i]); for(re i=1;i<=m;i++) rd(q[i].l),rd(q[i].r),rd(q[i].p),q[i].id=i,q[i].pos=(q[i].l-1)/len+1; sort(q+1,q+m+1,cmp); for(re i=1;i<=m;i++){ init_pow(q[i].p); while(l>q[i].l) --l,upd(l,1); while(r<q[i].r) ++r,upd(r,1); while(l<q[i].l) upd(l,-1),l++; while(r>q[i].r) upd(r,-1),r--; for(re j=qaq.lk[0].nxt;j;j=qaq.lk[j].nxt) ans[q[i].id]=((ans[q[i].id]+(ll)1ll*sum[j]*(get_pow(r-l+1,q[i].p)-get_pow(r-l+1-j,q[i].p))+q[i].p)%q[i].p+q[i].p)%q[i].p; } for(re i=1;i<=m;i++) wr(ans[i]),puts(""); return 0; }

__EOF__

本文作者Daniel Jiang
本文链接https://www.cnblogs.com/danieljiang/p/panjunwuwang.html
关于博主:JSOIer 高一萌新 求带/kel
版权声明:awa
声援博主:求赞/kel
posted @   Demoe  阅读(80)  评论(0编辑  收藏  举报
编辑推荐:
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· .NET Core 中如何实现缓存的预热?
· 三行代码完成国际化适配,妙~啊~
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
点击右上角即可分享
微信分享提示