JZOJ5946. 【NOIP2018模拟11.02】时空幻境(braid)

Description

Tim拥有控制时间的能力。他学会了BFS后,出了一道题:求出一张无向图中连通块的个数。他想请你做出这道题来
在这里插入图片描述
在这里插入图片描述

题解

其实跟bfs是没有关系的。
可以知道连边的点的编号是 x ∗ k i x*k^i xki
而在模意义下面, k i k^i ki是有循环节的,
考虑这个循环节长度len的奇偶性,
如果是奇数,考虑连边的情况,
也就在第一个循环的结尾与第一个位置连边,
然后第二个位置跟第三个位置连边,
这样一来,就构成了一个环。
所以这种情况下的连通块个数n-(len/2)
如果是偶数,点是两两连边,所以这个情况下的联通块个数就是n-(len-1)。
现在问题就变为了如果求循环节。
因为模数是质数,根据费马小定理就可以知道,
k m o − 1 k^{mo-1} kmo1同余1在模意义下。
假设 k a k^{a} ka同余1在模意义下,而且a是最小正数满足这个式子。
显然 k m o − 1 − i ∗ a k^{mo-1-i*a} kmo1ia也是满足的,也就可以知道a一定是mo-1的约数,
于是,因为mo-1是一个固定的数,可以先预处理好mo-1的所有约数, O ( n ) O(\sqrt n) O(n )
其实约数只有不到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)));
		}
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值