luogu4608 [FJOI2016]所有公共子序列问题
Posted liguanlin1124
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了luogu4608 [FJOI2016]所有公共子序列问题相关的知识,希望对你有一定的参考价值。
题目描述:
题解:
序列自动机(?)+高精+普及dp。
这个是猫老师的序列自动机(字符串从1开始):
void sol(char *s,int n,int t[N][53]) memset(t[n],-1,sizeof(t[n])); for(int i=n-1;i>=0;i--) memcpy(t[i],t[i+1],sizeof(t[i])); t[i][ci(s[i+1])] = i+1;
$t$数组记录在位置$i$的后面加字符$j$能到达的最左边的位置。
对于这道题,直接对两个串构造序列自动机,然后爆搜即可。
$k=1$没啥好说的,$k=0$高精压18位。
时间复杂度$O(n^2)$。
代码:
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; typedef long long ll; const int N = 3020; const ll M = 1000000000000000000ll; struct bignum ll a[10];//8 int len; void operator += (const bignum&x) int mx = max(len,x.len); for(int i=0;i<mx;i++) a[i]+=x.a[i]; if(a[i]>=M)a[i+1]+=a[i]/M,a[i]%=M; while(a[len])len++; void operator += (const ll&x) a[0]+=x; for(int i=0;a[i]>=M;i++)a[i+1]+=a[i]/M,a[i]%=M; while(a[len])len++; void write() if(!len)puts("0");return ; printf("%lld",a[len-1]); for(int i=len-2;i>=0;i--) printf("%018lld",a[i]); puts(""); dp[2500050]; int n,m,k,t1[N][53],t2[N][53],id[N][N],tot=0,ans=0; char s1[N],s2[N]; int ci(char ch) if(ch>=‘A‘&&ch<=‘Z‘)return ch-‘A‘; return ch-‘a‘+26; char ic(int i) if(i<26)return ‘A‘+i; return ‘a‘+i-26; void sol(char *s,int n,int t[N][53]) memset(t[n],-1,sizeof(t[n])); for(int i=n-1;i>=0;i--) memcpy(t[i],t[i+1],sizeof(t[i])); t[i][ci(s[i+1])] = i+1; int tl; char now[N]; void dfs1(int a,int b) for(int i=1;i<=tl;i++) putchar(now[i]); putchar(‘\n‘); ans++; for(int i=0;i<52;i++)if(~t1[a][i]&&~t2[b][i]) now[++tl] = ic(i); dfs1(t1[a][i],t2[b][i]); tl--; void dfs2(int a,int b) if(id[a][b])return ; id[a][b]=++tot; dp[tot]+=1; for(int i=0;i<52;i++)if(~t1[a][i]&&~t2[b][i]) dfs2(t1[a][i],t2[b][i]); dp[id[a][b]]+=dp[id[t1[a][i]][t2[b][i]]]; int main() // freopen("tt.in","r",stdin); scanf("%d%d%s%s%d",&m,&n,s1+1,s2+1,&k); sol(s1,m,t1),sol(s2,n,t2); if(k==1)dfs1(0,0);printf("%d\n",ans);return 0; dfs2(0,0);dp[id[0][0]].write(); return 0;
以上是关于luogu4608 [FJOI2016]所有公共子序列问题的主要内容,如果未能解决你的问题,请参考以下文章