题意:
给一个序列,序列值代表对应下标下一秒硬币要移动到的下标,再给一个相同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;}
新闻热点
疑难解答