并不对劲的bzoj4199: [Noi2015]品酒大会
传送门->
又称普及大会。
这题没什么好说的……后缀自动机裸题……并不对劲的人太菜了,之前照着标程逐行比对才过了这道题,前几天刚刚把这题一遍写对……
这题的输出和某两点相同后缀的长度有关,那么把串反过来就和相同前缀的长度有关。建出后缀自动机后,发现点u代表了right[u]个dis[fa[u]+1]~dis[u]相似的子串。此时如何统计答案就很显然了。
想着很简单,写着嘛…其实并不长?
#include<algorithm>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iomanip>
#include<iostream>
#include<map>
#include<queue>
#include<stack>
#include<vector>
#define rep(i,x,y) for(register LL i=(x);i<=(y);i++)
#define dwn(i,x,y) for(register LL i=(x);i>=(y);i--)
#define re register
#define maxn 600010
#define di ord[i]
#define LL long long
using namespace std;
inline LL read()
{
LL x=0,f=1;
char ch=getchar();
while(isdigit(ch)==0 && ch!='-')ch=getchar();
if(ch=='-')f=-1,ch=getchar();
while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
return x*f;
}
inline void write_(LL x)
{
LL f=0;char ch[20];
if(!x){putchar('0'),putchar(' ');return;}
if(x<0){putchar('-');x=-x;}
while(x)ch[++f]=x%10+'0',x/=10;
while(f)putchar(ch[f--]);
putchar(' ');
}
inline void writen(LL x)
{
LL f=0;char ch[20];
if(!x){puts("0");return;}
if(x<0){putchar('-');x=-x;}
while(x)ch[++f]=x%10+'0',x/=10;
while(f)putchar(ch[f--]);
putchar('\n');
}
LL ch[maxn][30],fa[maxn],r[maxn],dis[maxn],mn[maxn],mns[maxn],mx[maxn],mxs[maxn],lst,cnt;
LL cc[maxn],ord[maxn],rt,n,a[maxn],ans[maxn],num[maxn],inf[4];
char s[maxn];
LL gx(char c){return c-'a';}
void extend(char c)
{
LL np=++cnt,p=lst;dis[np]=dis[lst]+1,lst=np;
for(;p&&!ch[p][gx(c)];p=fa[p])ch[p][gx(c)]=np;
if(p==0)fa[np]=rt;
else
{
LL q=ch[p][gx(c)];
if(dis[q]==dis[p]+1)fa[np]=q;
else
{
LL nq=++cnt;dis[nq]=dis[p]+1;
fa[nq]=fa[q],fa[q]=fa[np]=nq;
memcpy(ch[nq],ch[q],sizeof(ch[q]));
for(;ch[p][gx(c)]==q;p=fa[p])ch[p][gx(c)]=nq;
}
}
}
void upd(LL x,LL y)
{
r[x]+=r[y];
if(mn[x]<mn[y])mns[x]=min(mns[x],mn[y]);
else mns[x]=min(mns[y],mn[x]),mn[x]=mn[y];
if(mx[x]>mx[y])mxs[x]=max(mxs[x],mx[y]);
else mxs[x]=max(mxs[y],mx[x]),mx[x]=mx[y];
}
LL mul(LL x)
{
LL tmx,tmn;
if(mx[x]!=-inf[0]&&mxs[x]!=-inf[0])tmx=mx[x]*mxs[x];
else tmx=-inf[0];
if(mn[x]!=inf[0]&&mns[x]!=inf[0])tmn=mn[x]*mns[x];
else tmn=-inf[0];
return max(tmx,tmn);
}
void qsort()
{
memset(cc,0,sizeof(cc));
rep(i,1,cnt)cc[dis[i]]++;
rep(i,1,n)cc[i]+=cc[i-1];
rep(i,1,cnt)ord[cc[dis[i]]--]=i;
}
int main()
{
n=read();
lst=rt=++cnt;dis[0]=-1;
scanf("%s",s+1);
rep(i,1,n)a[i]=read();
rep(i,1,(n>>1))swap(s[i],s[n-i+1]),swap(a[i],a[n-i+1]);
rep(i,1,n)extend(s[i]);
qsort();
memset(inf,0x7f,sizeof(inf));
rep(i,1,cnt)mx[i]=mxs[i]=ans[i]=-inf[0],mn[i]=mns[i]=inf[0];
LL p=rt;
rep(i,1,n)p=ch[p][gx(s[i])],mx[p]=mn[p]=a[i],r[p]=1;
dwn(i,cnt,1)upd(fa[di],di);
rep(i,1,cnt)
ans[dis[i]]=max(mul(i),ans[dis[i]]),
num[dis[fa[i]]+1]+=r[i]*(r[i]-1)/2,num[dis[i]+1]-=r[i]*(r[i]-1)/2;
dwn(i,n,1)ans[i]=max(ans[i],ans[i+1]);
rep(i,0,n-1)
num[i]+=num[i-1],write_(num[i]),
writen(num[i]==0?0:ans[i]);
return 0;
}
/*
10
ponoiiipoi
2 1 4 7 4 8 3 6 4 7
*/
据说用后缀数组也能做,不过思维难度略高。
要是觉得对后缀自动机还不够熟悉,可以试一下bzoj3238: [Ahoi2013],也是后缀自动机很好写(才怪)的题。
#include<algorithm>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iomanip>
#include<iostream>
#include<map>
#include<queue>
#include<stack>
#include<vector>
#define rep(i,x,y) for(register LL i=(x);i<=(y);++i)
#define dwn(i,x,y) for(register LL i=(x);i>=(y);--i)
#define re register
#define maxn 1000010
#define LL long long
using namespace std;
inline LL read()
{
LL x=0,f=1;
char ch=getchar();
while(isdigit(ch)==0 && ch!='-')ch=getchar();
if(ch=='-')f=-1,ch=getchar();
while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
return x*f;
}
inline void write(LL x)
{
LL f=0;char ch[20];
if(!x){puts("0");return;}
if(x<0){putchar('-');x=-x;}
while(x)ch[++f]=x%10+'0',x/=10;
while(f)putchar(ch[f--]);
putchar('\n');
}
LL ch[maxn][30],fa[maxn],dis[maxn],yes[maxn],lst,rt,cntnd;
LL v[maxn],nxt[maxn],fir[maxn],siz[maxn],ans[maxn],cntrd,len;
char s[maxn];
void ade(LL u1,LL v1){v[++cntrd]=v1,nxt[cntrd]=fir[u1],fir[u1]=cntrd;}//u->v
LL gx(char c){return c-'a';}
void extend(char c)
{
LL np=++cntnd,p=lst;dis[np]=dis[p]+1,lst=np;
for(;p&&ch[p][gx(c)]==0;p=fa[p])ch[p][gx(c)]=np;
if(!p)fa[np]=rt;
else
{
LL q=ch[p][gx(c)];
if(dis[q]==dis[p]+1)fa[np]=q;
else
{
LL nq=++cntnd;dis[nq]=dis[p]+1;
fa[nq]=fa[q],fa[np]=fa[q]=nq;
memcpy(ch[nq],ch[q],sizeof(ch[q]));
for(;ch[p][gx(c)]==q;p=fa[p])ch[p][gx(c)]=nq;
}
}
}
void getans(LL u)
{
if(yes[u])siz[u]=1;
LL tmp=0;
for(LL k=fir[u];k!=-1;k=nxt[k])
{
getans(v[k]);
siz[u]+=siz[v[k]];
}
for(LL k=fir[u];k!=-1;k=nxt[k])
tmp+=siz[v[k]]*(siz[u]-siz[v[k]]);
ans[u]=tmp*dis[u]+yes[u]*(siz[u]-1ll)*dis[u];
}
int main()
{
memset(fir,-1,sizeof(fir));
memset(ans,0,sizeof(ans));
lst=rt=++cntnd;dis[0]=-1;
scanf("%s",s+1);
len=strlen(s+1);
rep(i,1,len)swap(s[i],s[len-i+1]);
rep(i,1,len)extend(s[i]);
LL p=rt;
rep(i,1,cntnd)ade(fa[i],i);
rep(i,1,len)p=ch[p][gx(s[i])],yes[p]=1;
getans(rt);
LL ansans=0;
rep(i,1,cntnd)ansans+=ans[i];
write((len+1ll)*len*(len-1ll)/2ll-ansans);
return 0;
}
/*
cacao
*/
最后祝您身体健康,再见。
并不对劲的bzoj4199: [Noi2015]品酒大会的更多相关文章
- [UOJ#131][BZOJ4199][NOI2015]品酒大会 后缀数组 + 并查集
[UOJ#131][BZOJ4199][NOI2015]品酒大会 试题描述 一年一度的“幻影阁夏日品酒大会”隆重开幕了.大会包含品尝和趣味挑战两个环节,分别向优胜者颁发“首席品酒家”和“首席猎手”两个 ...
- [UOJ#131][BZOJ4199][NOI2015]品酒大会
[UOJ#131][BZOJ4199][NOI2015]品酒大会 试题描述 一年一度的“幻影阁夏日品酒大会”隆重开幕了.大会包含品尝和趣味挑战两个环节,分别向优胜者颁发“首席品酒家”和“首席猎手”两个 ...
- [bzoj4199][Noi2015]品酒大会_后缀自动机_后缀树_树形dp
品酒大会 bzoj-4199 Noi-2015 题目大意:给定一个字符串,如果其两个子串的前$r$个字符相等,那么称这两个子串的开头两个位置$r$相似.如果两个位置勾兑在一起那么美味度为两个位置的乘积 ...
- [BZOJ4199][NOI2015]品酒大会
#131. [NOI2015]品酒大会 统计 描述 提交 自定义测试 一年一度的“幻影阁夏日品酒大会”隆重开幕了.大会包含品尝和趣味挑战两个环节,分别向优胜者颁发“首席品酒家”和“首席猎手”两个奖项, ...
- bzoj4199: [Noi2015]品酒大会(后缀数组)
题目描述 一年一度的“幻影阁夏日品酒大会”隆重开幕了.大会包含品尝和趣味挑战 两个环节,分别向优胜者颁发“首席品酒家”和“首席猎手”两个奖项,吸引了众多品酒师参加. 在大会的晚餐上,调酒师 Rainb ...
- BZOJ4199 [Noi2015]品酒大会 【后缀数组 + 单调栈 + ST表】
题目 一年一度的"幻影阁夏日品酒大会"隆重开幕了.大会包含品尝和趣味挑战两个环节,分别向优胜者颁发"首席品 酒家"和"首席猎手"两个奖项,吸 ...
- 2019.02.28 bzoj4199: [Noi2015]品酒大会(sam+线段树)
传送门 题意:给一个串,每个位置有一个权值,当S[s...s+len−1]=S[t...t+len−1]&&S[s...s+len]̸=S[t..t+len]S[s...s+len-1 ...
- bzoj千题计划257:bzoj4199: [Noi2015]品酒大会
http://www.lydsy.com/JudgeOnline/problem.php?id=4199 求出后缀数组的height 从大到小枚举,合并 维护组内 元素个数,最大.次大.最小.次小 # ...
- [BZOJ4199][Noi2015]品酒大会 树形DP+后缀自动机
由于要找后缀的前缀,所以先用反串建立SAM. link边组成了后缀树. 两个子串的最长公共前缀是LCA的step 树形dp即可. #include<iostream> #include&l ...
随机推荐
- python023 Python3 标准库概览
Python3 标准库概览 操作系统接口 os模块提供了不少与操作系统相关联的函数. >>> import os >>> os.getcwd() # 返回当前的工作 ...
- 一段曲折的copy路程
cp 的时候出现:-bash: /bin/cp: Argument list too longcp ./*.swf /www/img/html/xxx/action/ 解决办法:find ./ -n ...
- 混合APP开发框架资料汇总
Ionic(ionicframework)一款接近原生的Html5移动App开发框架 会html css js就可以开发app,Ionic基于angualrjs框架是一个专注于开发移动wap以及app ...
- 前端学习之--html
html 文件就是充当模板使用,包含head头和body身体,body包含众多的标签,每个标签都使用尖括号包裹,内部由标签名和标签属性构成.其中标签分为2类: 1:块级标签,特点:占用一行,如:< ...
- 51 Nod 1244 莫比乌斯函数前n项和
积性函数前n项和必看好文 https://blog.csdn.net/skywalkert/article/details/50500009 递归计算的时候要用map记忆化一下,前面的打表会比较快一点 ...
- Educational Codeforces Round 50 (Rated for Div. 2)F. Relatively Prime Powers
实际上就是求在[2,n]中,x != a^b的个数,那么实际上就是要求x=a^b的个数,然后用总数减掉就好了. 直接开方求和显然会有重复的数.容斥搞一下,但实际上是要用到莫比乌斯函数的,另外要注意减掉 ...
- [Bzoj4540][Hnoi2016] 序列(莫队 + ST表 + 单调队列)
4540: [Hnoi2016]序列 Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 1567 Solved: 718[Submit][Status] ...
- Codeforces 938G(cdq分治+可撤销并查集+线性基)
题意: 有一个无向连通图,支持三个操作: 1 x y d : 新建一条x和y的无向边,长度为d 2 x y :删除x和y之间的无向边 3 x y :询问x到y的所有路径中(可以绕环)最短的 ...
- JAVA实验--统计文章中单词的个数并排序
分析: 1)要统计单词的个数,就自己的对文章中单词出现的判断的理解来说是:当出现一个非字母的字符的时候,对前面的一部分字符串归结为单词 2)对于最后要判断字母出现的个数这个问题,我认为应该是要用到ma ...
- 分享codeigniter框架,在zend studio 环境下的代码提示
一.到github下载相关文件 https://github.com/Stunt/Codeigniter-autocomplete 二.把文件放到application/config中 代码提示就出来 ...