把求逆序对的操作视为一个长度为p-1的数列进行置换
置换可以抽象为多个环和多个独立点
由线代的一个常识:交换任意两个位置逆序对的奇偶性发生变化,因此只需要讨论置换中交换的次数即点数-圈数即可
p-1 - 圈数
圈可以画成ax -> a^2x ->a^3x -> a^(k-1)x->ax
此时a^k在mod p下同余1
很自然的想到原根 即k=p-1时满足性质
那么又因为最小的k为置换中圈的长度,所以我们要求出最小的解d满足上述方程来求得圈数为(p-1)/d
直接求d需要枚举p-1的所有因数,在当前数据范围下不可能做到
我们回过头来发现只需要关注p-1 - 圈数的奇偶性即可
再化简到只需要观察(p-1)/d的奇偶性即可
而又表示为p-1 和 d中各自的2的因数个数是否相同即可
能满足a^k在mod p下同余1中的 k 一定能被d整除
假设p-1 = 2^t * q
因此我们考虑枚举 q 2q 4q ....... 2^tq作为d’
此时最小的d'一定有和d一样多的2的因子即可,枚举的次数为logn
而d‘|(p-1)/2的话可知d和p-1二因子个数肯定不同,所以问题又转化为直接检验a^((p-1)/2)是否同余1即可
题解做法:
相同的结论,只不过更加直观暴力
#include<bits/stdc++.h> using namespace std; #define LL long long #define LD long double #define ull unsigned long long const LL N=5e5+10; const LL INF=1e18; LL a,P,b; int cnt=0; void init(){ return; } void add(LL &x,LL y){ x+=y;if(x>=P)x-=P; } LL mul(LL x,LL y){ LL re=0; while(y){ if(y&1) add(re,x); add(x,x);y>>=1; } return re; } inline long long Mul(long long x,long long y){ long long tmp=(x*y-(long long)((long double)x/P*y+1.0e-8)*P); return (tmp+P)%P; } LL qpow(LL x,LL y){ LL re=1,re2; while(y){ if(y&1) { re=Mul(re,x); } x=Mul(x,x); y>>=1; } return re; } void MAIN(){ scanf("%lld%lld",&a,&P); b=qpow(a,(P-1)/2); if(b==1) { puts("0"); } else{ puts("1"); } return; } int main(){ init(); int ttt=1;scanf("%d",&ttt); while(ttt--) MAIN(); return 0; }