hdu 5475 LCS [循环节]

来源:互联网 发布:iphone 关闭移动数据 编辑:程序博客网 时间:2024/05/13 02:19

hdu 5475 LCS [循环节]

题目链接:hdu 5475 LCS 
题意:给定两个长度为N的 1~N的排列A, B。(1≤n≤10^5)  可以任意交换每一列,即让A[i],B[i] 同时移动。 问能构成的最长公共子序列的长度。
分析:找出循环节,然后答案就是 N - 循环节个数。
比如,对于样例2给定 的两个排列:
1 5 3 2 6 4
3 6 2 4 5 1
我们可以这样排列:
1 3 2 4  6 5
3 2 4 1  5 6

那么很容易发现,假设一个循环节长度为 k, 那么在这个循环节中的最长公共子序列就是k-1。那么初始化res = N,每增加一个循环节,res-- 即可。

#include <cmath>#include <queue>#include <vector>#include <cstdio>#include <string>#include <cstring>#include <iomanip>#include <iostream>#include <algorithm>using namespace std;using namespace std;#define FIN             freopen("input.txt","r",stdin)#define FOUT            freopen("output.txt","w",stdout)#define fst             first#define snd             secondtypedef __int64         LL;typedef pair<int, int>  PII;const int MAXN = 1e5 + 5;int T, N;int A[MAXN], B[MAXN];int RA[MAXN];bool vis[MAXN];int main() {#ifndef ONLINE_JUDGE    FIN;#endif // ONLINE_JUDGE    scanf("%d", &T);    while(T--) {        scanf("%d", &N);        for (int i = 0; i < N; i++) {            scanf("%d", &A[i]);            RA[A[i]] = i;        }        for (int i = 0; i < N; i++) {            scanf("%d", &B[i]);        }        memset(vis, false, sizeof(vis));        int cnt = 0, res = N, cur, rear;        for (int i = 0; i < N; i++) {            if(vis[A[i]]) continue;            rear = i;            if(A[i] != B[i]) res --;            while(!vis[A[rear]]) {                cur = rear;                vis[A[cur]] = true;                rear = RA[B[cur]];            }        }        printf("%d\n", res);    }    return 0;}

1 0
原创粉丝点击