【2020五校联考NOIP #4】今天的你依旧闪耀

题面传送门

题意:
对于一个长度为 \(n\)\(n\) 为偶数)的排列 \(p\),定义一次“变换”后得到的排列 \(p'\) 为:
\(p'_i=\begin{cases}p_{(i+n+1)/2}&&i \nmid 2\\p_{i/2}&&i\mid2\end{cases}\)
设函数 \(f(i)\)\(i\) 为偶数),如果长度为 \(i\) 的排列 \(p_j=j\) 经过 \(i\) 次变换恰好第一次回到原样,那么返回 \(i\),否则返回 \(0\)
现在给出一个偶数 \(A\),求 \([2,A]\) 中所有偶数的 \(f\) 的值的和。
\(2 \leq A \leq 10^7\)

不太难的题,简单写写吧。
容易注意到 \(i\) 经过一次变换变为 \(2i \bmod (n+1)\)
假设 \(1\) 经过 \(k\) 变换恰好回到 \(1\),那么有 \(2^k\equiv1\pmod{n+1}\)
两边同时乘上 \(i\) 得到 \(i2^k\equiv i\pmod{n+1}\)
也就是说如果 \(1\) 经过 \(k\) 变换恰好回到 \(1\),那么排列就会变回原样。
现在我们就变为对于每个 \(i\),判断 \(i\) 是否为最小的满足 \(2^k\equiv1\pmod{i+1}\)\(k\)
首先根据欧拉定理 \(2^{\varphi(i+1)}\equiv1\pmod{i+1}\),如果 \(i+1\) 不是质数,那么 \(\varphi(i+1)<i\)\(i\) 就不是最小的满足 \(2^k\equiv1\pmod{n+1}\)\(k\)
进一步观察,如果满足条件的 \(k\) 不是 \(i\),那么 \(k<i\)。将 \(i\) 分解质因数得到 \(p_1^{\alpha_1}\times p_2^{\alpha_2} \times\dots p_l^{\alpha_l}\)\(k\) 一定是 \(\frac{i}{p_1},\frac{i}{p_2},\dots,\frac{i}{p_l}\) 中某个数的约数。故我们只需检查 \(2^{\frac{i}{p_1}},2^{\frac{i}{p_2}},\dots,2^{\frac{i}{p_l}}\) 是否模 \(i+1\)\(1\) 就行了。
由于 \([1,n]\) 质因数个数最多也就 \(8\) 个,所以就算跑满了时间复杂度也不过 \(8\pi(n)\log n\),足以过这道题。

/*
Contest: -
Problem: NFLSOJ 701
Author: tzc_wk
Time: 2020.10.5
*/
#include <bits/stdc++.h>
using namespace std;
#define fi			first
#define se			second
#define pb			push_back
#define fz(i,a,b)	for(int i=a;i<=b;i++)
#define fd(i,a,b)	for(int i=a;i>=b;i--)
#define foreach(it,v) for(__typeof(v.begin()) it=v.begin();it!=v.end();it++)
#define all(a)		a.begin(),a.end()
#define fill0(a)	memset(a,0,sizeof(a))
#define fill1(a)	memset(a,-1,sizeof(a))
#define fillbig(a)	memset(a,0x3f,sizeof(a))
#define y1			y1010101010101
#define y0			y0101010101010
typedef pair<int,int> pii;
typedef long long ll;
inline int read(){
	int x=0,neg=1;char c=getchar();
	while(!isdigit(c)){
		if(c=='-') neg=-1;
		c=getchar();
	}
	while(isdigit(c)) x=x*10+c-'0',c=getchar();
	return x*neg;
}
int n=read();
bool vis[10000005];
int pr[10000005],pcnt=0;
int mnp[10000005];
inline ll qpow(ll x,int e,ll MOD){
	ll ans=1;
	while(e){
		if(e&1) ans=ans*x%MOD;
		x=x*x%MOD;e>>=1;
	}
	return ans;
}
inline void prework(int x){
	for(int i=2;i<=x;i++){
		if(!vis[i]){pr[++pcnt]=i;mnp[i]=i;}
		for(int j=1;j<=pcnt&&i*pr[j]<=x;j++){
			vis[i*pr[j]]=1;mnp[i*pr[j]]=pr[j];
			if(i%pr[j]==0) break;
		}
	}
}
int main(){
	prework(1e7);ll sum=0;
	for(int i=2;i<=n;i+=2){
		if(vis[i+1]) continue;
		bool flag=1;int tmp=i;
		vector<int> p;
		while(tmp!=1){
			int x=mnp[tmp];tmp/=x;
			if(p.empty()||p.back()!=x) p.pb(x);
		}
		for(int j=0;j<p.size();j++) if(qpow(2,i/p[j],i+1)==1) flag=0;
		if(flag) sum+=i;
	}
	printf("%.5lf\n",1.0*sum/(n>>1));
	return 0;
}

UPD on \(2020/10/19\)
洛 阳 铲(其实也就两周之前)
关于上文中“\(k\) 一定是 \(\frac{i}{p_1},\frac{i}{p_2},\dots,\frac{i}{p_l}\) 中某个数的约数”一句,一直有些疑惑,故刚刚 yy 了几分钟把它搞通了,今写在这里,以免下次再忘记。
我们假设最小的满足 \(2^k \equiv 1 \pmod{i+1}\)\(k\)\(l\),那么 \(2^{i-l} \equiv 1 \pmod{i+1}\)
反证法,假设 \(l\) 不是 \(i\) 的约数,那么 \(l \nmid i-l\)
\(i-l=pl+q(q<l)\),那么 \(2^{i-l}=2^{pl+q}=(2^l)^p\times 2^q\equiv 1^p\times 2^q=2^q\equiv 1\pmod{i+1}\)
\(2^q \equiv 1\pmod{i+1}\),又 \(q<l\),与我们之前的“\(l\) 是最小的满足 \(2^k \equiv 1 \pmod{i+1}\)\(k\)”矛盾。
\(l\)\(i\) 的约数。而 \(l \neq i\),所以 \(l\) 一定是 \(\frac{i}{p_1},\frac{i}{p_2},\dots,\frac{i}{p_l}\) 中某个数的约数。

posted @ 2020-10-06 11:19  tzc_wk  阅读(279)  评论(0编辑  收藏  举报