题意:

给定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 字符串重排的更多相关文章

  1. bzoj AC倒序

    Search GO 说明:输入题号直接进入相应题目,如需搜索含数字的题目,请在关键词前加单引号 Problem ID Title Source AC Submit Y 1000 A+B Problem ...

  2. uvaoj1339 - Ancient Cipher(思维题,排序,字符串加密)

    https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem& ...

  3. UVa 1339 Ancient Cipher --- 水题

    UVa 1339 题目大意:给定两个长度相同且不超过100个字符的字符串,判断能否把其中一个字符串重排后,然后对26个字母一一做一个映射,使得两个字符串相同 解题思路:字母可以重排,那么次序便不重要, ...

  4. codeforces 1093 题解

    12.18 update:补充了 $ F $ 题的题解 A 题: 题目保证一定有解,就可以考虑用 $ 2 $ 和 $ 3 $ 来凑出这个数 $ n $ 如果 $ n $ 是偶数,我们用 $ n / 2 ...

  5. LOJ2484 CEOI2017 Palindromic Partitions DP、回文树

    传送门 当我打开Luogu题解发现这道题可以Hash+贪心的时候我的内心是崩溃的-- 但是看到这道题不都应该认为这是一道PAM的练手好题么-- 首先把原字符串重排为\(s_1s_ks_2s_{k-1} ...

  6. 给定两个字符串 s 和 t,它们只包含小写字母。 字符串 t 由字符串 s 随机重排,然后在随机位置添加一个字母。 请找出在 t 中被添加的字母。

    给定两个字符串 s 和 t,它们只包含小写字母.字符串 t 由字符串 s 随机重排,然后在随机位置添加一个字母.请找出在 t 中被添加的字母. 示例: 输入: s = "abcd" ...

  7. 小b重排字符串

    2485 小b重排字符串 2 秒 262,144 KB 5 分 1 级题   小b有一个字符串S,现在她希望重排列S,使得S中相邻字符不同. 请你判断小b是否可能成功. 样例解释:将"aab ...

  8. 51nod 2485 小b重排字符串

    小b有一个字符串S,现在她希望重排列S,使得S中相邻字符不同. 请你判断小b是否可能成功. 样例解释:将"aab"重排为"aba"即可. 收起   输入 输入一 ...

  9. 【LeetCode】358.K 距离间隔重排字符串

    358.K 距离间隔重排字符串 知识点:哈希表:贪心:堆:队列 题目描述 给你一个非空的字符串 s 和一个整数 k,你要将这个字符串中的字母进行重新排列,使得重排后的字符串中相同字母的位置间隔距离至少 ...

随机推荐

  1. Time倒计时

    commitTimeDate = new Date("2016/11/9 10:02:40").getTime() + 24*60*60*1000;//截止时间 myDate = ...

  2. typedef struct与struct定义结构体

    今天在定义结构体的时候发现typedef struct与struct定义结构体有一些不同之处: 结构也是一种数据类型, 能够使用结构变量, 因此,  象其他 类型的变量一样, 在使用结构变量时要先对其 ...

  3. 一份还热乎的蚂蚁面经(已拿Offer)!附答案!!

    本文来自我的知识星球的球友投稿,他在最近的校招中拿到了蚂蚁金服的实习生Offer,整体思路和面试题目由作者--泽林提供,部分答案由Hollis整理自知识星球<Hollis和他的朋友们>中「 ...

  4. Django之sitemap

    ##########settings.py SITE_ID=1 # Application definition # taggit tag INSTALLED_APPS = [ 'myblog', ' ...

  5. vsftpd 虚拟用户限定在虚拟用户目录

    1.安装vsftpd yum -y install pam pam-devel db4 db4-tcl vsftpd 2.更名默认配置文件,以便恢复 cp /etc/vsftpd/vsftpd.con ...

  6. 疑问:使用find_elements_by_ios_predicate定位元素组,获取元素的index没有按照顺序

    通过ios Appium Inspect查看到的元素信息如下: eList=self.driver.find_elements_by_ios_predicate('type == “XCUIEleme ...

  7. HDU 5379 Mahjong tree(树的遍历&amp;组合数学)

    本文纯属原创,转载请注明出处.谢谢. http://blog.csdn.net/zip_fan 题目传送门:http://acm.hdu.edu.cn/showproblem.php? pid=537 ...

  8. 微信小程序页面布局之弹性布局-Flex介绍

    布局的传统解决方案,基于盒状模型,依赖 display 属性 + position属性 + float属性.它对于那些特殊布局非常不方便,比如,垂直居中就不容易实现. 2009年,W3C 提出了一种新 ...

  9. MessageDigest和DigestUtils加密算法

    总结:使用DigestUtils的方法加密的结果与messageDigest的方法加密结果一致,可使用DigestUtils替换MessageDigest 可省掉部分代码  package com.a ...

  10. HttpModule与HttpHandler详解(转)

    ASP.NET对请求处理的过程:当请求一个*.aspx文件的时候,这个请求会被inetinfo.exe进程截获,它判断文件的后缀(aspx)之后,将这个请求转交给 ASPNET_ISAPI.dll,A ...