HIHOcoder 1466 后缀自动机六·重复旋律9
思路
后缀数组+博弈论的好题,首先对两个串都建出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的更多相关文章
- hihoCoder #1445 : 后缀自动机二·重复旋律5
#1445 : 后缀自动机二·重复旋律5 时间限制:10000ms 单点时限:2000ms 内存限制:256MB 描述 小Hi平时的一大兴趣爱好就是演奏钢琴.我们知道一个音乐旋律被表示为一段数构成的数 ...
- 【hihoCoder 1466】后缀自动机六·重复旋律9
http://hihocoder.com/problemset/problem/1466 建出A串和B串的两个后缀自动机 对后缀自动机的每个状态求出sg值. 求出B串的\(sum(x)\),表示B有多 ...
- hihoCoder #1465 : 后缀自动机五·重复旋律8
http://hihocoder.com/problemset/problem/1465 求S的循环同构串在T中的出现次数 将串S变成SS 枚举SS的每个位置i,求出以i结尾的SS的子串 与 T的最长 ...
- hihocoder 1457 后缀自动机四·重复旋律7 求不同子串的和
描述 小Hi平时的一大兴趣爱好就是演奏钢琴.我们知道一段音乐旋律可以被表示为一段数构成的数列. 神奇的是小Hi发现了一部名字叫<十进制进行曲大全>的作品集,顾名思义,这部作品集里有许多作品 ...
- HIHOcoder 1457 后缀自动机四·重复旋律7
思路 后缀自动机题目,题目本质上是要求求出所有不同的子串的和,SAM每个节点中存放的子串互不相同,所以对于每个节点的sum,可以发现是可以递推的,每个点对子节点贡献是sum[x]*10+c*sz[x] ...
- hihocoder 1457 后缀自动机四·重复旋律7 ( 多串连接处理技巧 )
题目链接 分析 : 这道题对于单个串的用 SAM 然后想想怎么维护就行了 但是多个串下.可以先将所有的串用一个不在字符集( 这道题的字符集是 '0' ~ '9' ) 链接起来.建立后缀自动机之后 在统 ...
- hihoCoder #1457 : 后缀自动机四·重复旋律7(后缀自动机 + 拓扑排序)
http://hihocoder.com/problemset/problem/1457 val[i] 表示状态i所表示的所有字符串的十进制之和 ans= ∑ val[i]在后缀自动机上,从起始状态走 ...
- hihoCoder.1465.后缀自动机五 重复旋律8(后缀自动机)
题目链接 \(Description\) 给定母串S,求模式串的循环同构串在S中的出现次数. \(Solution\) 将模式串s复制一遍,在母串的SAM上匹配,记录以每个位置作为后缀所能匹配的最大长 ...
- HIHOcoder 1449 后缀自动机三·重复旋律6
思路 显然endpos的大小就对应了对应子串的出现次数,所以快速求出endpos的大小,然后用它更新对应子串长度(minlen[i]~maxlen[i])的答案即可 endpos的大小可以拓扑排序求出 ...
随机推荐
- Yii2 数据缓存/片段缓存/页面缓存/Http缓存
- Codeforces Round #324 (Div. 2) E
这题贪心,考虑先放第一个,然后从第一个数在p中的位置, 不断的往前走,和在他后面的那些数组进行交换,因为这样交换可以提高最大的效率,就是说你花费了1但是使得两个点都朝他的木匾节点减少了1 #inclu ...
- ecplise问题总结
ecplise 1.ecplise在运行的时候出现错误 Unable to execute dex: GC overhead limit exceeded GC overhead limit exce ...
- DNN模型训练词向量原理
转自:https://blog.csdn.net/fendouaini/article/details/79821852 1 词向量 在NLP里,最细的粒度是词语,由词语再组成句子,段落,文章.所以处 ...
- JAVA中获取文件MD5值的方法
1 DigestUtils.md5Hex(new FileInputStream(path)); 如果你只需要使用标准的MD5,其实一行代码就够了,JAVA自带的commons-codec包就提供了获 ...
- winscp 怎么用私钥文件登录的,以.ppk结尾的密钥文件
Winscp默认用帐号密码登录,用私钥文件登录需要在高级选项里面的SSH--验证里面选择文件. Winscp使用的是putty作为SSH登录工具,而puttygen所生成的是以.ppk结尾的密钥文件. ...
- 基于EOS开发的Dapp大全
基于EOS开发的Dapp大全 截止20180424,基于EOS开发的项目在50,很多项目的规划信息还不完善,搜集了基本的信息,供大家参考. ==========================长期囤币 ...
- [转载]ORA-01502错误成因和解决方法
检查一下索引状态,我们会注意到索引已经是“UNUSABLE”了.SQL> select index_name,index_type,tablespace_name,table_type,stat ...
- Python笔记 #19# 实现bpnn
代码编辑&解释工具:Jupyter Notebook 快速入门 形象说明BP神经网络的用法(图片来自推特): Bpnn类最主要的三个方法: initialize方法,用于设定神经网络的层数.各 ...
- django中的模型详解-1
在说明django模型之前,首先来说明一下django的生命周期,也就是一个请求到达django是如何处理的.[暂时不包含中间件] 浏览器的请求---->到达django中的urls中找到对应的 ...