#循环节,gcd#JZOJ 5362 密码

题目

询问一个排列\(A\)是否能够通过\(A_i=A_{A_i}\)得到,
同时还要满足给定的两个数通过加减或者交换能够得到已知的两个数


分析

下面的就是要保证\(\gcd\)相同,但是还有上面的操作(没看到qwq)
考虑它会分成很多个环,长度为奇数的环能够找到答案,
但是长度为偶数的环需要找到另一个长度相等的环缝合,即


代码

#include <cstdio>
#include <cctype>
#define rr register
using namespace std;
typedef long long lll;
lll A,B,GCD;
int T,n,a[41],v[41],cnt[41];
inline lll iut(){
	rr lll ans=0; rr char c=getchar();
	while (!isdigit(c)) c=getchar();
	while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
	return ans; 
}
inline lll gcd(lll x,lll y){return y?gcd(y,x%y):x;}
signed main(){
	freopen("pwd.in","r",stdin);
	freopen("pwd.out","w",stdout); 
	A=iut(),B=iut(),T=iut(),
	n=iut(),GCD=gcd(A,B);
	for (rr int i=1;i<=T;++i){
		rr bool flag=0;
		for (rr int j=1;j<=n;++j) a[j]=iut(),v[j]=cnt[j]=0; 
		for (rr int j=1;j<=n;++j)
		if (!v[j]){
			rr int z=a[j],len=1;
			for (;z!=j;z=a[z]) v[z]=1,++len;
			++cnt[len],v[j]=1;
		}
		for (rr int j=2;j<=n;j+=2)
		    if (cnt[j]&1) flag=1;
		rr lll X=iut(),Y=iut();
		if (gcd(X,Y)==GCD&&!flag) printf("Yes\n");
		    else printf("No\n");
    }
    return 0;
}
posted @ 2020-11-02 21:33  lemondinosaur  阅读(79)  评论(0编辑  收藏  举报