题意:
对于一个长度为 (n)((n) 为偶数)的排列 (p),定义一次“变换”后得到的排列 (p') 为:
(p'_i=egin{cases}p_{(i+n+1)/2}&&i
mid 2\p_{i/2}&&imid2end{cases})
设函数 (f(i)) ((i) 为偶数),如果长度为 (i) 的排列 (p_j=j) 经过 (i) 次变换恰好第一次回到原样,那么返回 (i),否则返回 (0)。
现在给出一个偶数 (A),求 ([2,A]) 中所有偶数的 (f) 的值的和。
(2 leq A leq 10^7)
不太难的题,简单写写吧。
容易注意到 (i) 经过一次变换变为 (2i mod (n+1))。
假设 (1) 经过 (k) 变换恰好回到 (1),那么有 (2^kequiv1pmod{n+1})
两边同时乘上 (i) 得到 (i2^kequiv ipmod{n+1})
也就是说如果 (1) 经过 (k) 变换恰好回到 (1),那么排列就会变回原样。
现在我们就变为对于每个 (i),判断 (i) 是否为最小的满足 (2^kequiv1pmod{i+1}) 的 (k)。
首先根据欧拉定理 (2^{varphi(i+1)}equiv1pmod{i+1}),如果 (i+1) 不是质数,那么 (varphi(i+1)<i),(i) 就不是最小的满足 (2^kequiv1pmod{n+1}) 的 (k)。
进一步观察,如果满足条件的 (k) 不是 (i),那么 (k<i)。将 (i) 分解质因数得到 (p_1^{alpha_1} imes p_2^{alpha_2} imesdots 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) 个,所以就算跑满了时间复杂度也不过 (8pi(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
",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
mid i-l)。
设 (i-l=pl+q(q<l)),那么 (2^{i-l}=2^{pl+q}=(2^l)^p imes 2^qequiv 1^p imes 2^q=2^qequiv 1pmod{i+1})
故 (2^q equiv 1pmod{i+1}),又 (q<l),与我们之前的“(l) 是最小的满足 (2^k equiv 1 pmod{i+1}) 的 (k)”矛盾。
故 (l) 为 (i) 的约数。而 (l
eq i),所以 (l) 一定是 (frac{i}{p_1},frac{i}{p_2},dots,frac{i}{p_l}) 中某个数的约数。