小 Z 上英语课思考数学问题被英语老师发现啦~
英语老师:「你这么爱胡思乱想我问你一道英语题吧」
小 Z 想跑,但是已经来不及了。
英语老师:「我们定义一个回文串是正方读起来相同的字符串」
小 Z:「这个简单,不就是像 " a b b a " "abba" "abba" " a b a " "aba" "aba"这样的吗」
英语老师:「现在给你一个长度为 n n n 的字符串,要你求出他的最长回文子序列」
小 Z:「子序列是不连续的吧? 好的我知道了」
小 Z 轻松的解决了这个问题,并把他修改了一下交给你。
现在一个字符串变成了 m m m 个数字,会魔法的小 Z 可以把一个数字 x x x 根据变换规则变成 y y y,给定所有的变换规则,要你求出这个数字串的最长回文子序列。
输入格式
第一行输入 3 个正整数 n n n, k k k 和 m m m, k k k 是转换规则的个数。
第二行开始的 k 行,每行两个正整数 x x x 和 y y y,表示数字 x x x 可以变成数字 y y y, 并且数字 y y y 可以变成数字 x x x。注意,如果数字 x x x 可以变成数字 y y y,并且数字 y y y 可以变成数字 z z z,那么数字 x x x 也可以便成数字 z z z。 x x x 可能等于 y y y,同一对 ( x , y ) (x, y) (x,y)可能重复出现。
最后一行输入 m m m 个正整数,表示题目中所提的数字串,每个数 ≤ n \le n ≤n。
输出格式
输出一行一个数表示答案。
数据范围
对于 20% 的数据: n , k , m ≤ 10 n,k,m\le10 n,k,m≤10;
对于 40% 的数据: n , k , m ≤ 200 n,k,m\le200 n,k,m≤200;
对于 100% 的数据: n ≤ 1 0 5 , k ≤ 1 0 6 , m ≤ 1 0 3 , 1 ≤ x , y ≤ n n \le 10^5,k \le 10^6,m \le 10^3,1 \le x,y \le n n≤105,k≤106,m≤103,1≤x,y≤n。
首先可以想到的是,对于可以互相转化的数字,把他们都变成一样的数字会有最优解。于是可以用并查集维护,将可以互相转化的数字合并,最后将每个数变成它的祖先。然后可以用Dp。定义 f [ i ] [ j ] f[i][j] f[i][j]为区间 [ i , j ] [i,j] [i,j]内的最长回文子序列,容易知道 f [ i ] [ i ] = 1 f[i][i]=1 f[i][i]=1。然后就可以知道:
f [ i ] [ j ] = max { f [ i + 1 ] [ j ] , f [ i ] [ j − 1 ] , f [ i + 1 ] [ j − 1 ] + 2 ( a [ i ] = = b [ j ] ) } f[i][j]=\max\{f[i+1][j],f[i][j-1],f[i+1][j-1]+2(a[i]==b[j])\} f[i][j]=max{f[i+1][j],f[i][j−1],f[i+1][j−1]+2(a[i]==b[j])}
然后就可以愉快的 A C AC AC了
#include
#include
#include
#include
using namespace std;
typedef long long LL;
const int N=1e5+5;
int f[N];
int d[1005][1005];
int n,k,m;
int a[1005],ans;
int getf(int x) {
return f[x]==x?x:f[x]=getf(f[x]);
}
int main() {
// freopen("d.in","r",stdin);
// freopen("d.out","w",stdout);
scanf("%d%d%d",&n,&k,&m);
for (int i=1;i<=n;i++) {
f[i]=i;
}
for (int i=1;i<=k;i++) {
int u,v;
scanf("%d%d",&u,&v);
u=getf(u);
v=getf(v);
if (u!=v) f[v]=u;
}
for (int i=1;i<=m;i++) {
scanf("%d",&a[i]);
a[i]=getf(a[i]);
d[i][i]=1;
}
for (int len=2;len<=m;len++) {
for (int i=1;i+len-1<=m;i++) {
int j=i+len-1;
if (a[i]==a[j]) d[i][j]=d[i+1][j-1]+2;
else d[i][j]=max(d[i][j-1],d[i+1][j]);
}
}
printf("%d",d[1][m]);
return 0;
}