bzoj2309 CTSC2011 字符串重排
题意:
给定n个字符串S1,S2,S3,...,Sn,把它们排序
设排序结果为Sp1,Sp2,Sp3,...,Spn
现在给定q个任务,每个任务的格式都是"要求在排序结果中Sa恰好在Sb前一个"
你排出的串满足第i个任务,就可以得到2^i(2的i次方)的奖励
现在有两个问题:
1.求相邻两项LCP平方和W的最大值
2.求出当W最大时能获得最多奖励的排序结果
数据&部分分:
对于 10%的数据,n ≤ 10,q = 1, 每个字符串的长度不超过 50;
对于 20%的数据,n ≤ 50,q = 1, 每个字符串的长度不超过 50;
对于 50%的数据,n ≤ 1000,q ≤ 1000, 每个字符串的长度不超过 1000;
对于 70%的数据,任意字符串不为其他任何一个字符串的前缀;
对于100%的数据, n ≤ 40 000, q ≤ 100 000, 每个字符串的长度不超过10 000;
对于 100%的数据,所有字符串的长度和不超过 200000。
bzoj坑爹啊,没有数据范围,还好Codevs上有
思路:
嗯,WJMZBMR远古巨神的神题,肯定不是我等一般人能做出来的
当然,在我有理有据的乱搞之前,我们先要确定这道题考的是啥
多个串,很像AC自动机,但LCP又跟AC自动机联系不起来,
苦苦思索2晚上无果后我的思路到了关键的一点:陈立杰在2012年的《后缀自动机讲稿》上有这么一句话
然后我就确定了:不会有后缀数据结构,毕竟CTSC也不太可能会出后缀数组
好,那么字符串还剩下什么数据结构呢
我们看数据范围的最后一条
答案脱口而出:Trie树!
对,就是Trie树大暴力
整理一下思路:我们明确两个大方向
(1)根据历史的进程,这道题一定是Trie树
(2)Trie树上的LCP,其实就是LCA的深度
好,现在我们开始做题
我们写一个动态Trie动态维护排序信息
别急,先打打暴力,看看有没有什么特殊性质
于是我在数学课上手算了4组数据发现
第一问是tm逗你玩的,W最大的情况是"字典序"
本来想着dp的我抱头痛哭
严谨证明的话...不太会
可能是在Trie树上搞个路径统计?
可以知道的是:一个字符串排列就相当于Trie树上一条从根出发回到根的路径
不知道,反正这一问在Trie树上按字典序dfs一下就好了
我们看第二问
第二问会发现,越往后奖励越多,所以我们考虑操作离线倒序,如果当前任务可以取就取到,然后更改Trie树上的路径(我就是在这yy出了LinkCutTrie的)
于是开始了漫长的手推
草稿纸都用了一张多,最后发现可以弄一个Trie链剖分+树套树
看了看前人的代码长度大概都是这么做的吧
然后在纸上写了很多乱七八糟的东西
...要滚去写作业了,幸运的是找到了曾经的题解
也算是看了一点点吧
毕竟还是个没学上的蒟蒻不可能一下子A掉CTSC的是不是?
放个链接吧
https://wenku.baidu.com/view/d6e7e02b647d27284b73516a.html?from=search
#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<vector>
#include<queue>
#define ll long long
using namespace std;
const int maxn=;
const int maxq=;
int n,q,dfn;
int x[maxq],y[maxq];
char SS[maxn];
struct Trie
{
Trie *ch[];
int Size,dep,rnk;
Trie *prev,*next;
Trie *first,*last;
Trie *father,*top;
Trie()
{
memset(ch,,sizeof(ch));
Size=;
father=;
prev=next=first=last=;
}
Trie *pre()
{
Trie *now;
for(now=this;now->prev;now=now->prev);
return now;
}
Trie *suf()
{
Trie *now;
for(now=this;now->next;now=now->next);
return now;
}
Trie *insert(int val)
{
Trie* &now=ch[val];
if (now==)
{
now=new Trie;
now->father=this;
Size++;
}
return now;
}
int count()
{
Trie *now=pre();
int cnt=;
while(now)
{
++cnt;
now=now->next;
}
return cnt;
}
bool find(Trie*o)
{
Trie *now=pre();
while(now)
{
if(now==o)return true;
now=now->next;
}
return false;
}
bool canFirst(Trie*c)
{
if (c==first)return true;
if (first != || c->prev != )return false;
if (c->suf()==last && c->count()!=Size)return false;
return true;
}
bool canLast(Trie*c)
{
if (c == last)return true;
if (last!= || c->next!=)return false;
if (c->pre()==first && c->count()!=Size)return false;
return true;
}
bool canNext(Trie*c1,Trie*c2)
{
if (c1->next==c2)return true;
if (c1->next!= || c2->prev!=)return false;
if (c1==last || c2==first)return false;
if (c1->find(c2))return false;
if (c1->pre()==first && c2->suf()==last && c1->count()+c2->count()<Size)return false;
return true;
}
void dfs(int de)
{
rnk=dfn++;
dep=de;
if(father==) top=;
else if(father->Size>)top=father;
else top=father->top;
for(int i=;i<;i++)if(ch[i]!=)ch[i]->dfs(dep+);
}
};
int todolis[maxq];
Trie *es[maxn],*ed[maxn],*rt;
Trie *getLCA(Trie *a, Trie *b)
{
while("woxihuan_keduoli")
{
if(a==b)return a;
if(a==rt || b==rt)return rt;
if( (a->top->dep) < (b->top->dep) )swap(a,b);
a=a->top;
}
}
void set(Trie *a,Trie *b)
{
Trie *l=getLCA(a,b);
while(a->top!=l)
{
Trie*fa=a->top;
fa->last=a;
a=fa;
}
while(b->top!=l)
{
Trie*fa=b->top;
fa->first=b;
b=fa;
}
a->next=b,b->prev=a;
}
bool check(Trie *a, Trie *b)
{
Trie *l=getLCA(a, b);
while(a->top!=l)
{
Trie*fa=a->top;
if(!fa->canLast(a))return false;
a=fa;
}
while(b->top!=l)
{
Trie*fa=b->top;
if(!fa->canFirst(b))return false;
b=fa;
}
if(!l->canNext(a,b))return false;
return true;
}
bool cmp(Trie*a, Trie*b){return (a->rnk) < (b->rnk);}
ll ans,cnt;
int main()
{
scanf("%d%d",&n,&q);
rt=new Trie;
for(int i=;i<n;i++)
{
scanf("%s",SS);
int len=strlen(SS);
Trie *temp=rt;
for(int j=;j<len;j++)temp=temp->insert(SS[j]-'a'+);
temp=temp->insert();
ed[i]=temp;
}
ll ans=;
rt->dfs();
for(int i=;i<q;i++) scanf("%d%d",&x[i],&y[i]),--x[i],--y[i];
for(int i=q-;i>=;i--)
if(check(ed[x[i]],ed[y[i]]))
{
set(ed[x[i]],ed[y[i]]);++cnt;todolis[i]=;
}
for(int i=;i<n;i++)es[i]=ed[i];
sort(es,es+n,cmp);
ll tmp;
for(int i=;i<n-;i++)
{
tmp=getLCA(es[i],es[i+])->dep;
ans+=tmp*tmp;
}
printf("%lld\n%lld\n",ans,cnt);
for(int i=;i<q;i++)if(todolis[i])printf("%d ",i+);
return ;
}
OI加油 期末加油
bzoj2309 CTSC2011 字符串重排的更多相关文章
- bzoj AC倒序
Search GO 说明:输入题号直接进入相应题目,如需搜索含数字的题目,请在关键词前加单引号 Problem ID Title Source AC Submit Y 1000 A+B Problem ...
- uvaoj1339 - Ancient Cipher(思维题,排序,字符串加密)
https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem& ...
- UVa 1339 Ancient Cipher --- 水题
UVa 1339 题目大意:给定两个长度相同且不超过100个字符的字符串,判断能否把其中一个字符串重排后,然后对26个字母一一做一个映射,使得两个字符串相同 解题思路:字母可以重排,那么次序便不重要, ...
- codeforces 1093 题解
12.18 update:补充了 $ F $ 题的题解 A 题: 题目保证一定有解,就可以考虑用 $ 2 $ 和 $ 3 $ 来凑出这个数 $ n $ 如果 $ n $ 是偶数,我们用 $ n / 2 ...
- LOJ2484 CEOI2017 Palindromic Partitions DP、回文树
传送门 当我打开Luogu题解发现这道题可以Hash+贪心的时候我的内心是崩溃的-- 但是看到这道题不都应该认为这是一道PAM的练手好题么-- 首先把原字符串重排为\(s_1s_ks_2s_{k-1} ...
- 给定两个字符串 s 和 t,它们只包含小写字母。 字符串 t 由字符串 s 随机重排,然后在随机位置添加一个字母。 请找出在 t 中被添加的字母。
给定两个字符串 s 和 t,它们只包含小写字母.字符串 t 由字符串 s 随机重排,然后在随机位置添加一个字母.请找出在 t 中被添加的字母. 示例: 输入: s = "abcd" ...
- 小b重排字符串
2485 小b重排字符串 2 秒 262,144 KB 5 分 1 级题 小b有一个字符串S,现在她希望重排列S,使得S中相邻字符不同. 请你判断小b是否可能成功. 样例解释:将"aab ...
- 51nod 2485 小b重排字符串
小b有一个字符串S,现在她希望重排列S,使得S中相邻字符不同. 请你判断小b是否可能成功. 样例解释:将"aab"重排为"aba"即可. 收起 输入 输入一 ...
- 【LeetCode】358.K 距离间隔重排字符串
358.K 距离间隔重排字符串 知识点:哈希表:贪心:堆:队列 题目描述 给你一个非空的字符串 s 和一个整数 k,你要将这个字符串中的字母进行重新排列,使得重排后的字符串中相同字母的位置间隔距离至少 ...
随机推荐
- MySQL的安装过程
近期对MySQL做了一些研究. 曾经主要接触的是SQL SERVER.所以,今天对该安装过程做了一些总结以及使用过程中的一些心得.并分享给大家. 记得前面.分享过一篇关于数据库的几种连接方式.而 ...
- Bootstrap学习速查表(一) 理论基础
参考网站http://www.bootcss.com/ 第一步,起步,引入基本样式 <!-- 新 Bootstrap 核心 CSS 文件 --> <link rel="st ...
- Map输出数据的处理类MapOutputBuffer分析
MapOutputBuffer顾名思义就是Map输出结果的一个Buffer,用户在编写map方法的时候有一个参数OutputCollector: void map(K1 key, V1 value, ...
- linux中likely()和unlikely()
likely()与unlikely()在2.6内核中,随处可见,那为什么要用它们?它们之间有什么区别呢?首先明确: if (likely(value))等价于if (value) if (unlike ...
- JS常用方法手记
1.判断arr数组是否含有元素str,没有返回-1 arr.indexOf(str) 2.遍历arr数组,k为键,v为值 arr.map((v, k) => { return;}) 3.arr数 ...
- map和string的使用方法
这个是别人写的map使用方法比較好能够看一下 http://www.cnblogs.com/anywei/archive/2011/10/27/2226830.html 怎样向数组中插入内容 http ...
- rtmp直播拉流客户端EasyRTMPClient TCP窗口大小设计方法
EasyRTMPClient 简介 EasyRTMPClient是EasyDarwin流媒体团队开发.提供的一套非常稳定.易用.支持重连接的RTMPClient工具,以SDK形式提供,接口调用非常简单 ...
- Chernoff-Hoeffding inequality -- Chernoff bounds, and some applications
https://www.cs.utah.edu/~jeffp/teaching/cs5955/L3-Chern-Hoeff.pdf [大数据-通过随机过程降维 ] When dealing with ...
- iOS 流布局 UICollectionView使用(使用FlowLayout进行更灵活布局)
在UICollectionView的布局中,如果每个item的大小都一样那么是十分简单的事情,但是,如果我们想要的每个item大小不一样呢,这个时候,就要对UICollectionViewFlowLa ...
- win10+UEFI下u盘安装ubuntu16.04
本人电脑是华硕,由于要求使用linux所以安装: 1.首先给linux划出一个大分区,感觉最少50G: win10下磁盘管理,在最后的分区中压缩出50g,空间,其他的不用问了,也不用继续分区,一个大的 ...