zoukankan      html  css  js  c++  java
  • 【2020五校联考NOIP #4】今天的你依旧闪耀

    题面传送门

    题意:
    对于一个长度为 (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}) 中某个数的约数。

  • 相关阅读:
    java 面向对象(二十二):关键字:final
    The Loss of Bounding Box Regression
    五大经典算法
    二叉树的深度优先遍历(前序、中序、后序)
    faster R-CNN中anchors 的生成过程
    快速排序
    __init__()
    好博客
    Focal Loss for Dense Object Detection(RetinaNet)(代码解析)
    Python获取 当前目录、上一级目录
  • 原文地址:https://www.cnblogs.com/ET2006/p/13772969.html
Copyright © 2011-2022 走看看