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

8 篇文章 0 订阅
1 篇文章 0 订阅

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。x\epsilon [1,\frac{n}{2}],x\epsilon Z

对于i是奇数且i < n:设上一个到 i 的位置为x,即x=(i+1+n)/2,有i=2x-n-1=2x-(n+1),即x->2x mod (n+1)。x\epsilon [\frac{n}{2},n],x\epsilon Z

因此,可以看成每一次操作将第x个位置上的数变成了2x mod (n+1)的位置,整个数列经过k次变化后第一个位置上的数又回到了

第一个位置,那么有:
2^k\equiv 1(mod~~ (n+1))

对于第x个位置上的数变化k次又回到x上,有:

x*2^k\equiv x(mod~~ (n+1))

因此,只需要第一个数回到了位置上,那么其他的数也会归位,也就得到了初始数列。

所以枚举第一个数,判断最小的k是否等于n。

时间复杂度O(n^2)

 

40%:

观察上面的式子,

2^k\equiv 1(mod~~ (n+1))

我们要判断使式子成立的最小的k是否为n。

因为n+1为奇数,所以gcd(2,n+1)=1,根据欧拉定理,有:

2^{\varphi(n+1)}\equiv 1(mod~~ (n+1))

如果n+1不是质数,那么1~n-1中至少有2个数不与n互质,即\varphi(n+1)<n,就一定存在一个更小的k不为n。

大概证明一下:如果n+1为合数,则n可表示为一个合数A和一个质数P的乘积,gcd(A,P)=1,所以有 

\varphi (n+1)=\varphi (A)*\varphi (P)=\varphi(A)*(P-1)=P *\varphi(A)-\varphi(A)

因为P*\varphi(A)<=P*A=n,且\varphi(A)>1,所以P *\varphi(A)-\varphi(A)<n

 

因此我们只需要考虑n+1为质数的情况。

如果存在一个k满足2^k\equiv 1(mod~~ (n+1)),那么(2^k)^t\equiv 1(mod~~ (n+1)),即k*t仍然满足条件。

因为已知当k=n时满足条件,因此更小的k只能是n的约数(kt=n),将n分解质因数得到n=\prod_{i=1}^{tot} p_i^{c_i},那么k至少是p1/n,p2/n...ptot/n中一个数的约数,即这些数中至少有一个满足2^{\frac{n}{p_i}}\equiv 1(mod (n+1)),那么只用枚举所有质因数用n/pi判断即可。

不同约数个数,在 10^7 范围内,不同的质因数个数最多的数也仅仅只有 8 个,其 它的数则远远达不到这个值。因此,在完全算满的情况下,判断个数为 O(\frac{n}{log~ n}),质因 数个数为 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;
}

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值