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}) 中某个数的约数。

  • 相关阅读:
    [BJOI2019] 光线
    C# 从零开始写 SharpDx 应用 笔刷
    BAT 脚本判断当前系统是 x86 还是 x64 系统
    BAT 脚本判断当前系统是 x86 还是 x64 系统
    win2d 通过 CanvasActiveLayer 画出透明度和裁剪
    win2d 通过 CanvasActiveLayer 画出透明度和裁剪
    PowerShell 拿到显卡信息
    PowerShell 拿到显卡信息
    win10 uwp 如何使用DataTemplate
    win10 uwp 如何使用DataTemplate
  • 原文地址:https://www.cnblogs.com/ET2006/p/13772969.html
Copyright © 2011-2022 走看看