bzoj4278[ONTAK2015]Tasowanie & bzoj1692[USACO 2007Dec]队列变换(Best Cow Line) 贪心正确性证明
做法网上到处都有就不说了.
这题其实是之前做的….不过由于人太傻现在才想明白比较字典序进行贪心的正确性….
方便起见,在两个串的最右端都加上很大但不相同的字符,避免第lcp+1个字符不存在的边界。
如果两个串当前最左端的字符不相同显然选较小的.
否则,设两个剩下的串的lcp长度为x,那么两个串的第lcp+1个字符(此时必然都存在这个字符,因为我们之前在右端加了很大的哨兵)必然不同.不妨假设第一个串的第lcp+1个字符较小.
考虑先选第二个串的第1个字符的某种方案.
如果这种方案中,我们先选了第二个串的第lcp+1个字符再选第一个串的第lcp+1个字符,那么把这种方案在选择第二个串的第lcp+1个字符之前的所有操作中选第一个串的操作改为选第二个串,选第二个串的操作改为选第一个串,最后把选择第二个串的第lcp+1个字符改为选择第一个串的第lcp+1个字符,这样得到先选第一个串的第1个字符且字典序更小的方案.
如果这种方案中,我们先选了第一个串的第lcp+1个字符,那么第一次操作后第一个串选了0个字符,第二个串选了1个字符.选择第一个串的第lcp+1个字符后,第一个串选了lcp+1个字符,第二个串选了<=lcp个字符.一开始第二个串选的字符多,最后第一个串选的字符多,因为每次只能进行一个操作,中间必然存在某次操作,使得这次操作后两个串选择的字符数目相同.那么我们把这次操作和这次操作之前的操作都反转一下(即:原先这次操作选第一个串,反转后这次操作选第二个串,原先选第二个串,反转后选第一个串),之后的操作不变,就可以得到一个字典序相同但是先选第一个串的第1个字符的方案.
于是,对于任何一个先选字典序较大的串的方案,我们都可以找到一个至少不会更差的方案先选字典序较小的串.因此最优方案必然是每次选择字典序较小的串.
某奶牛题poj3623&bzoj1692是从一个字符串两侧拿出字符组成字符串要求字典序最小,同样可以分这样两种情况考虑,由选字典序大的一侧方案得到选字典序小的一侧的方案,且使得最终结果不会更差.两侧开始的串的lcp可能会有重叠部分,拿这个串可能会拿着拿着拿到另一端,但仍然可以进行操作的反转,因此还是可以这么证.
#include<cstdio>
#include<algorithm>
using namespace std;
const int maxn=;
int sa[maxn],rank[maxn];
int tmp1[maxn],tmp2[maxn],key[maxn],sum[maxn];
int a[maxn];
void getsa(int n,int m){
int *rk=tmp1,*res=tmp2,i,j,p;
for(i=;i<m;++i)sum[i]=;
for(i=;i<n;++i)sum[rk[i]=a[i]]++;
for(i=;i<m;++i)sum[i]+=sum[i-];
for(i=n-;i>=;--i){
sa[--sum[rk[i]]]=i;
}
for(j=,p=;p<n;j<<=,m=p){
for(p=,i=n-j;i<n;++i)res[p++]=i;
for(i=;i<n;++i)if(sa[i]>=j)res[p++]=sa[i]-j;
for(i=;i<n;++i)key[i]=rk[res[i]];
for(i=;i<m;++i)sum[i]=;
for(i=;i<n;++i)sum[rk[i]]++;
for(i=;i<m;++i)sum[i]+=sum[i-];
for(i=n-;i>=;--i)sa[--sum[key[i]]]=res[i];
for(res[sa[]]=,p=,i=;i<n;++i){
if(sa[i]+j<n&&sa[i-]+j<n&&rk[sa[i]]==rk[sa[i-]]&&rk[sa[i]+j]==rk[sa[i-]+j])res[sa[i]]=p-;
else res[sa[i]]=p++;
}
swap(rk,res);
}
for(int i=;i<n;++i)rank[sa[i]]=i;
}
int main(){
int n,m;scanf("%d",&n);
for(int i=;i<n;++i)scanf("%d",&a[i]);
a[n]=;
scanf("%d",&m);
for(int i=;i<=m;++i)scanf("%d",&a[n+i]);
a[n+m+]=;
getsa(n+m+,); int pt1=,pt2=n+;
int lim=n+m;
for(int i=;i<=lim;++i){
printf("%d ",rank[pt1]>rank[pt2]?a[pt2++]:a[pt1++]);
}
return ;
}
#include<cstdio>
#include<cctype>
#include<algorithm>
using namespace std;
const int maxn=;
int tmp[][maxn],sum[maxn],key[maxn],sa[maxn],rank[maxn];
char str[maxn];
void getsa(int n,int m){
int i,j,k,p,*rk=tmp[],*res=tmp[];
for(i=;i<m;++i)sum[i]=;
for(i=;i<n;++i)sum[rk[i]=str[i]]++;
for(i=;i<m;++i)sum[i]+=sum[i-];
for(i=n-;i>=;--i)sa[--sum[rk[i]]]=i;
for(j=,p=;p<n;m=p,j<<=){
for(i=;i<m;++i)sum[i]=;
for(p=,i=n-j;i<n;++i)res[p++]=i;
for(i=;i<n;++i)if(sa[i]>=j)res[p++]=sa[i]-j;
for(i=;i<n;++i)sum[key[i]=rk[res[i]]]++;
for(i=;i<m;++i)sum[i]+=sum[i-];
for(i=n-;i>=;--i)sa[--sum[key[i]]]=res[i];
for(res[sa[]]=,p=,i=;i<n;++i){
res[sa[i]]=(rk[sa[i]]==rk[sa[i-]]&&rk[sa[i]+j]==rk[sa[i-]+j])?p-:p++;
}
swap(res,rk);
}
for(i=;i<n;++i)rank[sa[i]]=i;
}
int main(){
int n;scanf("%d",&n);
for(int i=;i<n;++i){
while(str[i]=getchar(),!isgraph(str[i]));
}
for(int i=;i<n;++i)str[n+i+]=str[n-i-];
str[n]='Z'+;str[*n+]='Z'+;
getsa(*n+,);
int pt1=,pt2=n+;
int cnt=;
for(int i=;i<=n;++i){
if(rank[pt1]<rank[pt2]){
printf("%c",str[pt1]);pt1++;
}else{
printf("%c",str[pt2]);pt2++;
}
cnt++;
if(cnt%==)printf("\n");
}
return ;
}
bzoj4278[ONTAK2015]Tasowanie & bzoj1692[USACO 2007Dec]队列变换(Best Cow Line) 贪心正确性证明的更多相关文章
- bzoj1640[Usaco2007 Nov]Best Cow Line 队列变换*&&bzoj1692[Usaco2007 Dec]队列变换*
bzoj1640[Usaco2007 Nov]Best Cow Line 队列变换 bzoj1692[Usaco2007 Dec]队列变换 题意: 有一个奶牛队列.每次可以在原来队列的首端或是尾端牵出 ...
- [bzoj1692][Usaco2007 Dec]队列变换_后缀数组_贪心
队列变换 bzoj-1692 Usaco-2007 Dec 题目大意:给定一个长度为$n$的字符串.每次从头或尾取出一个字符加到另一个字符串里.要求变换后生成的字符串字典序最小,求字典序最小的字符串. ...
- 【BZOJ-1692&1640】队列变换 后缀数组 + 贪心
1692: [Usaco2007 Dec]队列变换 Time Limit: 5 Sec Memory Limit: 64 MBSubmit: 1153 Solved: 482[Submit][St ...
- BZOJ1692: [Usaco2007 Dec]队列变换
1692: [Usaco2007 Dec]队列变换 Time Limit: 5 Sec Memory Limit: 64 MBSubmit: 594 Solved: 246[Submit][Sta ...
- [bzoj1692] [Usaco2007 Dec]队列变换 (hash||暴力)
本题同bzoj1640...双倍经验双倍幸福 虽然数据范围n=3w然而O(n²)毫无压力= = http://blog.csdn.net/xueyifan1993/article/details/77 ...
- BZOJ4278 : [ONTAK2015]Tasowanie
首先在串的末尾加上1000,然后进行归并,每次取字典序较小的那个后缀即可. 用hash+二分支持查询lcp,时间复杂度$O(n\log n)$. #include<cstdio> type ...
- [bzoj1692][Usaco2007 Dec]队列变换——贪心+后缀数组
Brief Description 给定一个数列,您每次可以把数列的最前面的数或最后面的数移动到新数列的开头,使得新数列字典序最小.输出这个新序列. Algorithm Design 首先我们可以使用 ...
- BZOJ4278 [ONTAK2015]Tasowanie[后缀数组+贪心]
题目 求两数组归并后的数组最小字典序排列. 嘛,可能本人在贪心这块还是太弱了(或者说什么都弱),如果不知道是字符串题估计也想不起来用sa. 显然看得出归并时字典序小的那个数组先往里面加,这就是要比较两 ...
- [BZOJ4278] [ONTAK2015]Tasowanie 贪心+后缀数组
题目链接 最近做题目好像有点东一榔头西一棒.好吧其实订正模拟题的时候需要用到什么感觉不太熟的就写一下吧. 显然直接贪心,比较两个点后面的串的字典序,小就选谁就可以了. 可以把两个串接起来,加一个\(i ...
随机推荐
- sas简单使用
1 数据存取: 逻辑库: libname 自己起的名字 ‘文件所在的路径’,若无这步数据则存在默认的work中. 另一个方法在sas里自己建立一个逻辑库,但是关闭后就消失了. 新建数据:data ...
- 路由追踪:traceroute/tcptraceroute
一.工作原理 traceroute:IP路由过程中对数据包TTL(Time to Live,存活时间)进行处理.当路由器收到一个IP包时,会修改IP包的TTL(及由此造成的头部检验和checksum变 ...
- 长沙Uber优步司机奖励政策(12月21日到12月27日)
滴快车单单2.5倍,注册地址:http://www.udache.com/ 如何注册Uber司机(全国版最新最详细注册流程)/月入2万/不用抢单:http://www.cnblogs.com/mfry ...
- cakephp中find('list')的使用
运用一.快速实现下拉菜单 控制器中,使用find('list')返回的是键值对的数组,键名是array的第一个参数id,键值就是第二个参数content. public function list_s ...
- Tomcat7后台通过get接收数据处理乱码
Tomcat7后台通过get接收数据处理乱码 //因为tomcat7 默认将用get传来的数据用ISO-8859-1封装, //将ajax传过来的值解码,再转码,//因为tomcat7 默认将用get ...
- android 学习十四 探索安全性和权限
1.部署安全性:应用程序必须使用数字证书才能安装到设备上. 2.执行期间的安全性: 2.1 使用独立进程 2.2 使用固定唯一用户ID 2.3 申明性权限模型 3数字证书 ...
- JS dataTables
原文地址: http://www.cnblogs.com/haogj/archive/2011/03/04/1971328.html 数据来源有四种: 1. 网页DOM对象 $(document) ...
- JavaWeb项目生成PDF文件添加水印图片并导出
一.前言 首先需要在Maven中添加相应的jar包依赖,若项目没用到Maven,也可自行下载相应所需的jar包(itextpdf.jar 与 itext-asian.jar),如下图所示.点此下载 M ...
- Java开发工程师(Web方向) - 01.Java Web开发入门 - 第1章.Web应用开发概述
第1章--Web应用开发概述 Web应用开发概述 浏览器-服务器架构(BS-architecture) browser/ App ---- request ----> server ...
- 【WXS数据类型】Array
属性: 名称 值类型 说明 [Array].constructor [String] 返回值为“Array”,表示类型的结构字符串 [Array].length [Number] 返回数组长度 方法: ...