BZOJ4567: [Scoi2016]背单词
Posted f321dd
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了BZOJ4567: [Scoi2016]背单词相关的知识,希望对你有一定的参考价值。
题面原文大致如下:
有n个单词,从小到大填入表,对于序号为x的单词(1~x-1都已被填入):
- 如果存在一个单词是它的后缀,并且当前没有被填入表内,代价为n*n;
- 当它的所有后缀都被填入表内的情况下,如果在1~x-1的位置上的单词都不是它的后缀,代价为x;
- 当它的所有后缀都被填入表内的情况下,如果1~x-1的位置上存在是它后缀的单词,所有是它后缀的单词中,序号最大为y,代价为x-y。
求最小代价。
写题面的人脑子打了结吧能写出这种见鬼的描述,逻辑被狗吃了。
第二个条件相当于说:当它的所有后缀都被填入表内的情况下,表内的单词都不是它的后缀。
这句子是人写出来的吗。
然后你必须推导出这句话的意思是:“它的所有后缀”为空集。
而“它的所有后缀”是指是它的后缀的所有单词。
最后把这个题面翻译成人话就是:
- 如果存在一个单词是它的后缀,且当前没被填入,代价为n*n;
- 如果不存在一个单词是它的后缀,代价为x;
- 如果存在一个单词是它的后缀,且已填入的是它后缀的单词中序号最大的为y,代价为x-y。
然后就是个sb贪心。
我还能说什么呢。
只有我一个人读不懂题吗,真是惨无人道。
#include<bits/stdc++.h> #define S t[u][z[j]-97] #define I t[u][i] #define pb push_back #define RAN(v)v.begin(),v.end() #define FOR(i,v) for(typeof(v.end())i=v.begin();i!=v.end();++i) using namespace std; typedef long long ll; const int N=100005; const int M=510005; int n,tot; char z[M]; int t[M][26],l[M],r[N]; ll f[N]; vector<int>e[N]; bool foo(int i,int j){ return r[i]<r[j]; } void dfs1(int u,int v){ if(l[u])e[v].pb(l[u]); for(int i=0;i<26;++i) if(I)dfs1(I,l[u]?l[u]:v); } void dfs2(int u){ r[u]=1; FOR(i,e[u]) dfs2(*i),r[u]+=r[*i]; sort(RAN(e[u]),foo); f[u]=1; int s=0; FOR(i,e[u]) f[u]+=f[*i]+s,s+=r[*i]; } int main(){ scanf("%d",&n); for(int i=1;i<=n;++i){ scanf("%s",z); int u=0; for(int j=strlen(z)-1;~j;--j) u=S?S:S=++tot; l[u]=i; } dfs1(0,0),dfs2(0); printf("%lld\n",f[0]-1); }
以上是关于BZOJ4567: [Scoi2016]背单词的主要内容,如果未能解决你的问题,请参考以下文章