Description
世界可以抽象成一个长度为偶数n 且元素互不相同的数列a。每当发生了一些意外,他都会相应的产生一些变化,并成为一个新的数列a′,并且它们满足以下关系:
如果这个数列正好经过n 次变换后首次回到最初始的数列a ,这个世界便是幸运的。此时的幸运值是n;如果没有回到最初始的序列,幸运值便是0。
那如果,这个序列的长度在[2,A] 之间的偶数内均匀随机时,请你告诉我,世界期望的幸运值是多少呢?
Input
输入一行一个正整数A,其意义见【题目描述】。
Output
输出一行一个实数,表示我的幸运值的期望,请保留5 位小数。
Sample Input
6
Sample Output
2.00000
Data Constraint
Hint
【输入输出样例1 说明】
n = 2 时我的幸运值为2,n = 4 时我的幸运值为4,n = 6 时我的幸运值为0,所
以我的幸运值的期望为2。
Solution
10%:
直接模拟,O(n^3)
30%:
发现整个过程只需要判断一下所有的环的大小的gcd是否为n。
时间复杂度O(n^2 log n)
进一步发现:
对于i是偶数且i<=n:设上一个到 i 的位置为x,即x=i/2,有i=2x,即x->2x。
对于i是奇数且i < n:设上一个到 i 的位置为x,即x=(i+1+n)/2,有i=2x-n-1=2x-(n+1),即x->2x mod (n+1)。
因此,可以看成每一次操作将第x个位置上的数变成了2x mod (n+1)的位置,整个数列经过k次变化后第一个位置上的数又回到了
第一个位置,那么有:
对于第x个位置上的数变化k次又回到x上,有:
因此,只需要第一个数回到了位置上,那么其他的数也会归位,也就得到了初始数列。
所以枚举第一个数,判断最小的k是否等于n。
时间复杂度O(n^2)
40%:
观察上面的式子,
我们要判断使式子成立的最小的k是否为n。
因为n+1为奇数,所以gcd(2,n+1)=1,根据欧拉定理,有:
如果n+1不是质数,那么1~n-1中至少有2个数不与n互质,即,就一定存在一个更小的k不为n。
大概证明一下:如果n+1为合数,则n可表示为一个合数A和一个质数P的乘积,gcd(A,P)=1,所以有
因为,且
,所以
因此我们只需要考虑n+1为质数的情况。
如果存在一个k满足,那么
,即k*t仍然满足条件。
因为已知当k=n时满足条件,因此更小的k只能是n的约数(kt=n),将n分解质因数得到,那么k至少是p1/n,p2/n...ptot/n中一个数的约数,即这些数中至少有一个满足
,那么只用枚举所有质因数用n/pi判断即可。
不同约数个数,在 10^7 范围内,不同的质因数个数最多的数也仅仅只有 8 个,其 它的数则远远达不到这个值。因此,在完全算满的情况下,判断个数为 ,质因 数个数为 O(8),快速幂为 O(log n),总复杂度也仅仅只有 O(8n),足以通过所有数据。
Code
#include<cstdio>
#define I int
#define ll long long
#define db double
#define F(i,a,b) for(register I i=a;i<=b;i++)
#define N 10000003
#define M 998244353
using namespace std;
I n,bz[N],d[N],p[665000],x;
db ans;
I ksm(ll x,I k,I p){
ll s=1;
for(;k;k>>=1,x=(x*x)%p) if(k&1) s=(s*x)%p;
return s;
}
I main(){
freopen("world.in","r",stdin);
freopen("world.out","w",stdout);
scanf("%d",&n);
F(i,2,n+1){
if(!bz[i]) p[++p[0]]=d[i]=i;
F(j,1,p[0]){
if(i*p[j]>n+1) break;
bz[i*(d[i*p[j]]=p[j])]=1;
if(i%p[j]==0) break;
}
}
for(register I i=2;i<=n;i+=2) if(!bz[i+1]){
bz[0]=1;x=i;
while(x>1){
if(ksm(2,i/d[x],i+1)==1){bz[0]=0;break;}
x/=d[x];
}
(bz[0])?ans+=i:1;
}
printf("%.05lf",ans/(n>>1));
return 0;
}