GMOJ 6832. 【2020.10.24 NOIP提高A组】world

世界可以抽象成一个长度为偶数n 且元素互不相同的数列a。每当发生了一些意外,他都会相应的产生一些变化,并成为一个新的数列a′,并且它们满足以下关系:

如果这个数列正好经过n 次变换后首次回到最初始的数列a ,这个世界便是幸运的。此时的幸运值是n;如果没有回到最初始的序列,幸运值便是0。
那如果,这个序列的长度在[2,A] 之间的偶数内均匀随机时,请你告诉我,世界期望的幸运值是多少呢?

这是本场比赛最水的一题,但是因为这题卡时间,所以我也调了很久。
将式子化简,可以发现,每次变换实际上是:x->2x%(n+1)
所以,我们只需要判断2^n=1(% n+1)且n是最小的满足条件的数即可。
有欧拉定理可得,当n+1不是质数时,ϕ(n+1)就会小于n,此时n就一定不是最小的了。
所以,我们只需要判断质数的情况。
然后可以发现,如果n有一个约数也满足条件,则说明这个约数一定是n除以某个质因子的因子,所以n除以这个质因子肯定也满足条件。
然后可以发现,10000000万以内的数,最多只有8个不同质因子,所以可以直接快速幂判断。
时间复杂度:质数个数O(n/log(n))
质因子个数8*快速幂时间复杂度log(n),也就是O(8n)

#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 10000010
#define db double
#define ll long long
#pragma GCC optimize(3)
#pragma GCC optimize("Ofast")
using namespace std;
int n,i,j,k,x,bz[N],tot,q[N],bzk,pri[N],cnt;
ll ans;
ll mi(int x,int n,int mo){
	if (n==1) return x;
	ll sum=mi((ll)x*x%mo,n/2,mo);
	if (n%2) sum=sum*x%mo;
	return sum;
}
int main(){
	freopen("world.in","r",stdin);
	freopen("world.out","w",stdout);
	scanf("%d",&n);
	bz[1]=1;
	for (i=2;i<=n+1;i++){
		if (!bz[i]) pri[++cnt]=i;
		for (j=1;j<=cnt;j++){
			if (i*pri[j]>n+1) break;
			bz[i*pri[j]]=1;
			if (i%pri[j]==0) break;
		}
	}
	
	
	for (i=2;i<=n;i+=2)
		if (!bz[i+1]){
			bzk=0;
			x=i;
			for (j=1;pri[j]*pri[j]<=i;j++)
				if (x%pri[j]==0){
					if (mi(2,i/pri[j],i+1)==1){	
						bzk=1;
						break;
					}
					while (x%pri[j]==0) x/=pri[j];
				}
			if (x>1&&mi(2,i/x,i+1)==1)
				bzk=1;
			if (!bzk) ans+=i;
		}
	printf("%.5lf
",(db)ans/(n/2));
	return 0;
}
原文地址:https://www.cnblogs.com/Mohogany/p/13871373.html