CF1286E-Fedya the Potter Strikes Back【KMP,RMQ】

1|0正题

题目链接:https://www.luogu.com.cn/problem/CF1286E


1|1题目大意

定义一个字符串s的权值为对于每个sLR=s1RL+1的区间,会产生mini=LRwi的贡献。

现在开始时s为空串,n次往s后加入一个字符和往w序列加入一个数字,然后求这个串的贡献。

强制在线

1n6×105,1wi<230


1|2解题思路

我们在每次加入字符后考虑所有后缀的贡献,然后考虑加入一个字符后后缀产生贡献的变化。

一个想法是对于原来的后缀[nlen,n1],如果slen+1=sn,那么新的后缀[nlen,n]就会产生贡献,否则就不会。除了这些以外还有如果s1=sn那么后缀[n,n]也会产生贡献。

也就是一次操作最多增加一个会产生后缀的贡献,我们取考虑怎么维护其他以前的后缀。

权值方面比较简单,[nlen,n1]的贡献转到[nlen,n]的贡献无非就是对wimin,也就是我们要一个能支持加入删除全部取min的数据结构。其实暴力维护都行,我们用map记录贡献为k的后缀有多少个,然后每次暴力把大于wi的都修改掉即可,这样势能分析一下就知道是对的。

现在第二个问题是我们怎么知道每次要删除的后缀是哪些。我们建立出KMP的fail树,那么原本产生贡献的后缀肯定都在n1点到根节点的路径上,我们维护一个lasi,c表示节点i往祖先走的路上遇到的第一个x满足sx+1=cx,然后我们就可以一直往上走找到要删除的后缀了。

RMQ维护一下后缀的贡献即可。

时间复杂度:O(nlogn)


1|3code

#include<cstdio> #include<cstring> #include<algorithm> #include<map> #define ll long long using namespace std; const ll N=6e5+10,mod=1e18; ll n,lg[N],nxt[N],las[N][26],ans; char s[N];map<ll,ll> mp;int f[N][20]; pair<ll,ll> sum; pair<ll,ll> operator+(const pair<ll,ll> &x,const ll &y) {return make_pair((x.first+y)%mod,x.second+(x.first+y)/mod);} ll operator%(const pair<ll,ll> &x,const ll &p) {return (x.first%p+(x.second%p)*(mod%p)%p)%p;} void print(pair<ll,ll> x) { if(x.second) printf("%lld%018lld\n",x.second,x.first); else printf("%lld\n",x.first); } ll Ask(ll l,ll r){ ll z=lg[r-l+1]; return min(f[r][z],f[l+(1<<z)-1][z]); } signed main() { scanf("%lld",&n); for(ll i=2;i<=n;i++)lg[i]=lg[i>>1]+1; ll mask=(1ll<<30),z=0; char op[2];ll w=0; scanf("%s%lld",op,&w); mp[w]++;ans=sum.first=w; s[1]=op[0];f[1][0]=w; printf("%lld\n",ans); for(ll p=2;p<=n;p++){ scanf("%s%lld",op,&w); char c=op[0]; c=(c-97+sum%26)%26+97;s[p]=c; w=w^(sum%mask);f[p][0]=w; for(ll i=1;(1<<i)<=p;i++) f[p][i]=min(f[p][i-1],f[p-(1<<i-1)][i-1]); while(z&&s[z+1]!=s[p])z=nxt[z]; nxt[p]=(z+=(s[z+1]==s[p])); for(ll j=0;j<26;j++)las[p][j]=las[nxt[p]][j]; las[p][s[nxt[p]+1]-'a']=nxt[p]; for(ll j=0;j<26;j++){ if(j+'a'==c)continue; for(ll x=las[p-1][j];x;x=las[x][j]){ ll val=Ask(p-x,p-1); mp[val]--;ans=ans+(-val); } } while(mp.size()){ map<ll,ll>::iterator it=mp.end();it--; pair<ll,ll> x=*it; if(x.first>w){ ans=ans+(-(x.first-w)*x.second); mp[w]+=x.second;mp.erase(it); } else break; } if(s[p]==s[1])mp[w]++,ans=ans+w; sum=sum+ans;print(sum); } return 0; }

__EOF__

本文作者QuantAsk
本文链接https://www.cnblogs.com/QuantAsk/p/16573826.html
关于博主:退役OIer,GD划水选手
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   QuantAsk  阅读(54)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 张高兴的大模型开发实战:(一)使用 Selenium 进行网页爬虫
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
历史上的今天:
2021-08-10 P7737-[NOI2021]庆典【tarjan,虚树】
2021-08-10 P5494-[模板]线段树分裂
2021-08-10 2021“MINIEYE杯”中国大学生算法设计超级联赛(7)部分题解
2021-08-10 jzoj7212-[2022省赛]染色(color)【根号分治】
点击右上角即可分享
微信分享提示