世界可以抽象成一个长度为偶数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;
}