思路

后缀数组+博弈论的好题,首先对两个串都建出SAM,然后题目的要求实际上就是在SAM的trans上转移即可

DAG的博弈是经典问题,然后dfs求出SG函数,两个游戏的组合就是把SG函数异或起来,异或是0就是先手必败,不是0就是先手必胜

然后要求先手必胜,所以就是求异或不为0

接下来递推的求出第k大的串即可,类似于树上的第k大的思路

代码

#include <cstdio>
#include <algorithm>
#include <cstring>
#define int long long
using namespace std;
const int MAXN = 100100*2;
struct SAM{
int trans[MAXN][26],suflink[MAXN],maxlen[MAXN],sg[MAXN],cnt;
long long cnt_sg[MAXN][28];
int new_state(int _maxlen,int *_trans,int _suflink){
++cnt;
maxlen[cnt]=_maxlen;
if(_trans)
for(int i=0;i<26;i++)
trans[cnt][i]=_trans[i];
suflink[cnt]=_suflink;
return cnt;
}
int add_len(int u,int c){
int z=new_state(maxlen[u]+1,NULL,0);
while(u&&(!trans[u][c])){
trans[u][c]=z;
u=suflink[u];
}
if(!u){
suflink[z]=1;
return z;
}
int v=trans[u][c];
if(maxlen[v]==maxlen[u]+1){
suflink[z]=v;
return z;
}
int y=new_state(maxlen[u]+1,trans[v],suflink[v]);
suflink[z]=suflink[v]=y;
while(u&&trans[u][c]==v){
trans[u][c]=y;
u=suflink[u];
}
return z;
}
int cal_sg(int u){
if(sg[u]!=-1)
return sg[u];
bool mid[30]={0};
for(int i=0;i<26;i++){
if(!trans[u][i])
continue;
int t=cal_sg(trans[u][i]);
mid[t]=true;
for(int j=0;j<27;j++)
cnt_sg[u][j]+=cnt_sg[trans[u][i]][j];
}
for(int i=0;i<30;i++)
if(!mid[i]){
sg[u]=i;
break;
}
cnt_sg[u][sg[u]]++;
for(int i=0;i<27;i++)
cnt_sg[u][27]+=cnt_sg[u][i];
return sg[u];
}
void init(char *s,int len){
int pre=1;
cnt=1;
for(int i=1;i<=len;i++)
pre=add_len(pre,s[i]-'a');
memset(sg,-1,sizeof(sg));
cal_sg(1);
}
}A,B;
int lena,lenb,mida;
long long k;
char sa[MAXN],sb[MAXN],ax[MAXN],bx[MAXN];
long long calc_mid(int Ax,int Bx){
long long ans=0;
for(int i=0;i<27;i++)
ans+=A.cnt_sg[Ax][i]*(B.cnt_sg[Bx][27]-B.cnt_sg[Bx][i]);
return ans;
}
int dfsA(int pos,int x){
int mid1=B.cnt_sg[1][27]-B.cnt_sg[1][A.sg[x]];
if(mid1>=k)
return x;
else
k-=mid1;
for(int i=0;i<26;i++){
if(!A.trans[x][i])
continue;
int mid2=calc_mid(A.trans[x][i],1);
if(mid2<k)
k-=mid2;
else{
ax[pos]='a'+i;
return dfsA(pos+1,A.trans[x][i]);
}
}
return -1;
}
int dfsB(int pos,int x){
k-=B.sg[x]!=A.sg[mida];
if(k==0)
return x;
for(int i=0;i<26;i++){
if(!B.trans[x][i])
continue;
int mid2=B.cnt_sg[B.trans[x][i]][27]-B.cnt_sg[B.trans[x][i]][A.sg[mida]];
if(mid2<k)
k-=mid2;
else{
bx[pos]='a'+i;
return dfsB(pos+1,B.trans[x][i]);
}
}
return -1;
}
signed main(){
scanf("%lld",&k);
scanf("%s",sa+1);
lena=strlen(sa+1);
scanf("%s",sb+1);
lenb=strlen(sb+1);
A.init(sa,lena);
B.init(sb,lenb);
if((mida=dfsA(1,1))==-1){
printf("NO\n");
return 0;
}
dfsB(1,1);
printf("%s\n",ax+1);
printf("%s\n",bx+1);
return 0;
}

HIHOcoder 1466 后缀自动机六·重复旋律9的更多相关文章

  1. hihoCoder #1445 : 后缀自动机二·重复旋律5

    #1445 : 后缀自动机二·重复旋律5 时间限制:10000ms 单点时限:2000ms 内存限制:256MB 描述 小Hi平时的一大兴趣爱好就是演奏钢琴.我们知道一个音乐旋律被表示为一段数构成的数 ...

  2. 【hihoCoder 1466】后缀自动机六·重复旋律9

    http://hihocoder.com/problemset/problem/1466 建出A串和B串的两个后缀自动机 对后缀自动机的每个状态求出sg值. 求出B串的\(sum(x)\),表示B有多 ...

  3. hihoCoder #1465 : 后缀自动机五·重复旋律8

    http://hihocoder.com/problemset/problem/1465 求S的循环同构串在T中的出现次数 将串S变成SS 枚举SS的每个位置i,求出以i结尾的SS的子串 与 T的最长 ...

  4. hihocoder 1457 后缀自动机四·重复旋律7 求不同子串的和

    描述 小Hi平时的一大兴趣爱好就是演奏钢琴.我们知道一段音乐旋律可以被表示为一段数构成的数列. 神奇的是小Hi发现了一部名字叫<十进制进行曲大全>的作品集,顾名思义,这部作品集里有许多作品 ...

  5. HIHOcoder 1457 后缀自动机四·重复旋律7

    思路 后缀自动机题目,题目本质上是要求求出所有不同的子串的和,SAM每个节点中存放的子串互不相同,所以对于每个节点的sum,可以发现是可以递推的,每个点对子节点贡献是sum[x]*10+c*sz[x] ...

  6. hihocoder 1457 后缀自动机四·重复旋律7 ( 多串连接处理技巧 )

    题目链接 分析 : 这道题对于单个串的用 SAM 然后想想怎么维护就行了 但是多个串下.可以先将所有的串用一个不在字符集( 这道题的字符集是 '0' ~ '9' ) 链接起来.建立后缀自动机之后 在统 ...

  7. hihoCoder #1457 : 后缀自动机四·重复旋律7(后缀自动机 + 拓扑排序)

    http://hihocoder.com/problemset/problem/1457 val[i] 表示状态i所表示的所有字符串的十进制之和 ans= ∑ val[i]在后缀自动机上,从起始状态走 ...

  8. hihoCoder.1465.后缀自动机五 重复旋律8(后缀自动机)

    题目链接 \(Description\) 给定母串S,求模式串的循环同构串在S中的出现次数. \(Solution\) 将模式串s复制一遍,在母串的SAM上匹配,记录以每个位置作为后缀所能匹配的最大长 ...

  9. HIHOcoder 1449 后缀自动机三·重复旋律6

    思路 显然endpos的大小就对应了对应子串的出现次数,所以快速求出endpos的大小,然后用它更新对应子串长度(minlen[i]~maxlen[i])的答案即可 endpos的大小可以拓扑排序求出 ...

随机推荐

  1. HTML5特性&&canvas

    1.HTML5是由W3C(万维网联盟,专注于XHTML 2.0)和WHATWG(专注于web表单和应用程序)共同合作的结果,2014年10月完成标准制定! 主要设计目的:为了在移动设备上支持多媒体. ...

  2. CSS选择符-----属性选择符

       Element[att] 选择具有att属性的E元素 <!DOCTYPE html> <html> <head> <meta charset=" ...

  3. .net web site 和 web application 的区别

    web application 会把所有的代码编译打包成单一的库文件(.dll). web site 不会对整个的代码进行编译,在运行时须要哪一段代码就编译哪段代码.这导致web site 上线后,如 ...

  4. Redis入门——安装与基本命令

    1. Redis安装 下载地址:https://github.com/MSOpenTech/redis/releases 下载zip文件后直接解压 2. 启动Redis服务端 解压目录下执行redis ...

  5. sql server启动服务和还原bak文件

    sql server启动服务和还原bak文件, sql server启动要: mysql数据库备份是psc后缀文件, sql server还原数据库备份bak文件: 三张图简介明了: ok:

  6. 转:【专题七】UDP编程补充——UDP广播程序的实现

    上次因为时间的关系,所以把上一个专题遗留下的一个问题在本专题中和大家分享下,本专题主要介绍下如何实现UDP广播的程序,下面就直接介绍实现过程和代码以及运行的结果. 一.程序实现 UDP广播程序的实现代 ...

  7. django -- 修改admin 密码问题

    1.python manage.py shell 2.from django.contrib.auth.models import User 3.user=User.objects.get(usern ...

  8. centos7 安装zabbix

    一.安装mysql 1.[root@iZ28gvqe4biZ ~]# rpm -Uvh http://dev.mysql.com/get/mysql-community-release-el7-5.n ...

  9. 左移和右移运算符<< >>

    左移的符号为<< 首先来个简单的例子    求8左移两位的值  8<<2   首先 将十进制的8转为二进制的数    倒序输出----> 1000 1000  左移两位 ...

  10. C++形参中const char * 与 char * 的区别

    在函数调用时,我们经常看见一个函数的接受参数为(const char *); 例如strlen()函数,它的定义为: size_t strlen( const char *str); 那么将形参设置为 ...