JZOJ5946. 【NOIP2018模擬11.02】時空幻境(braid)
阿新 • • 發佈:2018-12-19
Description
Tim擁有控制時間的能力。他學會了BFS後,出了一道題:求出一張無向圖中連通塊的個數。他想請你做出這道題來
題解
其實跟bfs是沒有關係的。 可以知道連邊的點的編號是 而在模意義下面,是有迴圈節的, 考慮這個迴圈節長度len的奇偶性, 如果是奇數,考慮連邊的情況, 也就在第一個迴圈的結尾與第一個位置連邊, 然後第二個位置跟第三個位置連邊, 這樣一來,就構成了一個環。 所以這種情況下的連通塊個數n-(len/2) 如果是偶數,點是兩兩連邊,所以這個情況下的聯通塊個數就是n-(len-1)。 現在問題就變為了如果求迴圈節。 因為模數是質數,根據費馬小定理就可以知道, 同餘1在模意義下。 假設同餘1在模意義下,而且a是最小正數滿足這個式子。 顯然也是滿足的,也就可以知道a一定是mo-1的約數, 於是,因為mo-1是一個固定的數,可以先預處理好mo-1的所有約數,。 其實約數只有不到100個,非常少, 對於輸入的每一個k,就可以直接從小到大列舉約數,判斷一下就可以了。
code
#include<cstdio> #include<algorithm> #define ll long long using namespace std; char ch; void read(int&n) { for(ch=getchar();ch<'0'|| ch>'9';ch=getchar()); for(n=0;'0'<=ch && ch<='9';ch=getchar())n=(n<<1)+(n<<3)+ch-48; } int T,n,m,x,k,s[103],ans; ll ksm(ll x,int y) { ll s=1; for(;y;y>>=1,x=x*x%n) if(y&1)s=s*x%n; return s; } int main() { n=998244352; for(int i=1;i*i<=n;i++) if(n%i==0)s[++s[0]]=i,s[++s[0]]=n/i; sort(s+1,s+1+s[0]); freopen("braid.in","r",stdin); freopen("braid.out","w",stdout); for(read(T);T;T--) { read(n);read(m);read(x);read(k); if(k==1)printf("%d\n",n);else { for(int i=1;i<=s[0];i++) if(ksm(k,s[i])==1) { ans=s[i]; break; } if(ans&1)ans--;else ans=ans>>1; printf("%d\n",max(1,n-min(ans,m))); } } }