cf 759 A Pavel and barbecue

96 篇文章 0 订阅
13 篇文章 0 订阅

题意:

给一个序列,序列值代表对应下标下一秒硬币要移动到的下标,再给一个相同01序列,1代表在这个位置下一秒硬币翻转。问需要修改几次这两个序列使得每一枚硬币经过若干秒后能以正面和反面的姿态都经过过每一个点。


解题思路:

之所以需要修改是硬币的移动位置会形成循环,而这个循环有可能不是全局的,是分成几堆硬币内部循环,我们需要找出这样硬币的堆数,如果堆数是一那么正好不用改,如果大于一就需要把这几堆硬币串联再一起,需要的修改数量就是堆数。

而翻转的序列就很好考虑了,我们只考虑一枚硬币,这枚硬币经过其它所以点回到原来点后,如果翻转次数是偶数,那么回来时的状态和出发时的状态是一样的,这样就会循环下去,那么肯定是不可以正反两面都经过每一个点的,所以要求翻转的次数是奇数。


代码:

#include <bits/stdc++.h>

using namespace std;
const int maxn=2e5;
int add[maxn];
bool rev[maxn];
bool vis[maxn];
int main()
{
    int n;
    scanf("%d", &n);
    int i;
    for(i=1; i<=n; i++)scanf("%d", &add[i]);
    int cir=0;
    for(i=1; i<=n; i++)
    {
        if(vis[i])continue;
        cir++;
        int t=i;
        do
        {
            vis[t]=1;
            t=add[t];
        }while(i!=t);
    }
    int odd=0;
    for(i=1; i<=n; i++){scanf("%d", &rev[i]);if(rev[i])odd++;}
    int ans=0;

//    printf("%d\n", ans);


    if(odd%2==0)ans++;
    printf("%d\n", ans+(cir>1?cir:0));
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值