gmoj 6832.world
Description
世界可以抽象成一个长度为偶数n 且元素互不相同的数列a。每当发生了一些意外,他都会相应的产生一些变化,并成为一个新的数列a′,并且它们满足以下关系:
如果这个数列正好经过n 次变换后首次回到最初始的数列a ,这个世界便是幸运的。此时的幸运值是n;如果没有回到最初始的序列,幸运值便是0。
那如果,这个序列的长度在[2,A] 之间的偶数内均匀随机时,请你告诉我,世界期望的幸运值是多少呢?
Input
输入一行一个正整数A,其意义见【题目描述】。
Outout
输出一行一个实数,表示我的幸运值的期望,请保留5 位小数。
Solution
对于第i个位置,经过k次变换后到达的位置应该是\(i\times2^k\ \%\ (n+1)\)
而对于第一个位置到达的的位置就是\(2^k\ \%(n+1)\)
所以回到第一个位置即\(2^k\equiv1(mod\ n+1)\)
所以现在要求的是这个最小的k
根据欧拉定理,\(2^{\phi(n+1)}\equiv1(mod\ n+1)\)
所以如果\(\phi(n+1)\) 小于n,则n就不会是最小的k
因为当n+1为质数是\(\phi(n+1)\) 才会是n,所以当n+1为质数时才判断这个n
但这个n不一定是最小的
当n不是最小的时候,最小的一定是n的因数(讲真挺好证的,画个图,因为\(y=2^x\ mod\ (n+1)\)这东西的y是循环的,所以要使刚好在n那等于1,则最小的那个数应该是n的因数)
把n分解质因数,最多就8个数,所以时间复杂度\(O(8n)\) 可以接受
Code
#include <cstdio>
#include <algorithm>
#include <cmath>
#define N 10000001
#define open(x) freopen(x".in","r",stdin);freopen(x".out","w",stdout);
using namespace std;
int i,j,cnt,tot,n,x,ma,prime[N],a[N],last[N];
long long ans;
bool bz[N];
long long ksm(long long x,int y,int MO)
{
long long sum=1;
while (y)
{
if (y&1)sum=sum*x%MO;
x=x*x%MO;
y>>=1;
}
return sum;
}
int main()
{
open("world");
scanf("%d",&n);
for (i=2;i<=n;i++)
{
if (!bz[i]) prime[++tot]=i;
for (j=1;j<=tot;j++)
{
if (prime[j]*i>n) break;
bz[prime[j]*i]=1;
last[prime[j]*i]=prime[j];
if (i%prime[j]==0) break;
}
}
for (i=2;i<=n;i+=2)
{
if (bz[i+1]) continue;
x=i;
ma=0;
if (ksm(2,i,i+1)==1) ma=i;
while (last[x])
{
cnt=last[x];
while (x%cnt==0) x/=cnt;
if (ksm(2,i/cnt,i+1)==1)
{
ma=i/cnt;
break;
}
}
if (x>1)
{
if (!ma) ma=i/x;else
if (ksm(2,i/x,i+1)==1 && ma==i) ma=i/x;
}
if (ma==i) ans+=i;
}
printf("%.5Lf",ans/(long double)(n/2));
return 0;
}
如果自己说什麽都做不到而什麽都不去做的话,那就更是什麽都做不到,什麽都不会改变,什麽都不会结束.