题意:给出n个数,(a_i)代表下一步会移动到第(a_i)个位置,并继续进行操作,(b_i)1代表进行一次翻面操作,要求不管以哪个位置上开始,最后都能满足
1.到达过所有位置
2.对到达的任意位置,都已经进行过奇次和偶次翻面操作
交换任意两个(a_i),或修改(b_i)的值算做一次操作
问最小操作数。
思路:首先可以知道,要满足条件1,必须使该排列的循环节长度为1(即所有数成一个环),再者要满足条件2,则(b_i==1)必须有奇数个。
那么很简单,对所有未标记的数dfs一遍,进行的dfs次数就是循环节长度,再统计(b_i)中1的个数即可。
/** @Date : 2017-04-09 21:10:36 * @FileName: 760C DFS.cpp * @Platform: Windows * @Author : Lweleth (SoundEarlf@gmail.com) * @Link : https://github.com/Lweleth * @Version : $Id$ */ #include<bits/stdc++.h> #define LL long long #define PII pair #define MP(x, y) make_pair((x),(y)) #define fi first #define se second #define PB(x) push_back((x)) #define MMG(x) memset((x), -1,sizeof(x)) #define MMF(x) memset((x),0,sizeof(x)) #define MMI(x) memset((x), INF, sizeof(x)) using namespace std; const int INF = 0x3f3f3f3f; const int N = 2e5+20; const double eps = 1e-8; int a[N], b[N]; int vis[N]; void dfs(int x) { vis[x] = 1; if(vis[a[x]] == 0) dfs(a[x]); } int main() { int n; while(cin >> n) { MMF(vis); for(int i = 1; i <= n; i++) scanf("%d", a + i); for(int i = 1; i <= n; i++) scanf("%d", b + i); int ans = 0; int cnt = 0; for(int i = 1; i <= n; i++) { if(!vis[i]) dfs(i), ans++; if(b[i]) cnt++; } if(ans == 1) ans--; printf("%d ", ans + ((cnt%2)?0:1)); } return 0; }