把求逆序對的操作視為一個長度為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; }