zoukankan      html  css  js  c++  java
  • Pavel and barbecue

    题目链接

    CF756A

    题目

    Pavel cooks barbecue. There are n skewers, they lay on a brazier in a row, each on one of n positions. Pavel wants each skewer to be cooked some time in every of n positions in two directions: in the one it was directed originally and in the reversed direction.

    Pavel has a plan: a permutation p and a sequence b 1, b 2, ..., b n, consisting of zeros and ones. Each second Pavel move skewer on position i to position p i, and if b i equals 1 then he reverses it. So he hope that every skewer will visit every position in both directions.

    Unfortunately, not every pair of permutation p and sequence b suits Pavel. What is the minimum total number of elements in the given permutation p and the given sequence b he needs to change so that every skewer will visit each of 2n placements? Note that after changing the permutation should remain a permutation as well.

    There is no problem for Pavel, if some skewer visits some of the placements several times before he ends to cook. In other words, a permutation p and a sequence b suit him if there is an integer k ( k ≥ 2n), so that after k seconds each skewer visits each of the 2n placements.

    It can be shown that some suitable pair of permutation p and sequence b exists for any n.

    Input
    The first line contain the integer (n (1 ≤ n ≤ 2·10^5)) — the number of skewers.

    The second line contains a sequence of integers (p_1, p_2, ..., p_n (1 ≤ p_i ≤ n)) — the permutation, according to which Pavel wants to move the skewers.

    The third line contains a sequence (b_1, b_2, ..., b_n) consisting of zeros and ones, according to which Pavel wants to reverse the skewers.

    Output
    Print single integer — the minimum total number of elements in the given permutation p and the given sequence b he needs to change so that every skewer will visit each of 2n placements.

    Examples
    Input

    4
    4 3 2 1
    0 1 1 1
    

    Output

    2
    

    Input

    3
    2 3 1
    0 0 0
    

    Output

    1
    

    Note
    In the first example Pavel can change the permutation to 4, 3, 1, 2.

    In the second example Pavel can change any element of b to 1.

    题意

    有n个位置和n个肉串,需要把每个串串在每个地方两面都烤过才可以吃,现在有一个序列p,(p_i)表示在放在i的肉串下一个都被放到(p_i)。有序列b,当(b_i)为1时,这个位置要进行翻面。让你对p和b的元素进行最少的修改,让所有肉串都能吃。

    思路

    • 理解一下第一个样例的NOTE的4,3,1,2:

      • 对于第一个位置的肉串:1->4->2->3->1->4->2->3->1...,于此同时翻面:0->1->0->1->1->0->1->0->0->...。 第二个:2->3->1->4->2->3->1->4->2...,...
      • 每个肉串都正反两面在所有地方烤了。
      • 观察看看,有环,而且两个环里面正反面不同。
    • 让每个肉串在每个地方烤过

      • 意思就是p可以成一个环,这样每个地方的肉串都可以绕一圈又一圈,去到每个地方。
      • 判断环可以用dfs
      • 对于原来给的p序列,不能成一个环的话,会成多个环,例如样例1的p会成两个环。我们的目标是一个环,所以要将多个环合成一个环。观察一下,就可以发现,x个环合成一个环最少要修改x条边。每个环修改一条。
      • 注意如果本身就1个环的话,就不需要修改了,否则有多少环修改多少次。
    • 让每个肉串在每个地方两面都烤过

      • 意思就是一个环绕两圈,这一圈的每个面要和上一圈的面不一样。
      • 要让第二圈的面和第一圈的面不同,那么第一次绕回原点的时候,原点的面应该和一开始的时候的面不一样了,要实现这个,就只要保证这一圈中翻面的次数是奇数就好了。
      • 如果翻面次数是偶数,那修改次数要+1,用来增加/减少一次翻面。

    代码

    #include<bits/stdc++.h>
    using namespace std;
    const int MAXN=200005;
    int n;
    int p[MAXN],b[MAXN];
    bool vis[MAXN];
    void dfs(int x){
    	while(!vis[x]){
    		vis[x]=true;
    		x=p[x];
    	}
    }
    int main(){
    	scanf("%d",&n);
    	int ans=0;
    	for(int i=1;i<=n;i++) scanf("%d",&p[i]);
    	int cnt=0;
    	for(int i=1;i<=n;i++){
    		scanf("%d",&b[i]);
    		if(b[i]==1) cnt++;
    	}
    	if(cnt%2==0) ans++;
    	cnt=0;
    	for(int i=1;i<=n;i++){
    		if(vis[i]) continue;
    		dfs(i);
    		cnt++;
    	}
    	if(cnt!=1) ans+=cnt;
    	printf("%d
    ",ans);
    	return 0;
    }
    
  • 相关阅读:
    大数加法、乘法实现的简单版本
    hdu 4027 Can you answer these queries?
    zoj 1610 Count the Colors
    2018 徐州赛区网赛 G. Trace
    1495 中国好区间 尺取法
    LA 3938 动态最大连续区间 线段树
    51nod 1275 连续子段的差异
    caioj 1172 poj 2823 单调队列过渡题
    数据结构和算法题
    一个通用分页类
  • 原文地址:https://www.cnblogs.com/xuwanwei/p/12833841.html
Copyright © 2011-2022 走看看