题意:给出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;
}