• 【BZOJ3884】上帝与集合的正确用法


    Description

      
      一句话题意,给定(p)作为模数:
      
    img
      
      (ple 10^7),数据组数(Tle1000)
      
      
      

    Solution

      
      看到就弃疗了,再见......
      
      将模数(p)拆分成(p=q2^k),其中(q)为一个奇数。那么:
      
      

    [egin{aligned} 2^{2^{2...}}mod; p&=2^k(2^{2^{2..}-k}mod;q)\ &=2^k(2^{(2^{2..}-k)mod;varphi(q)}mod;q) end{aligned} ]

      考虑递归计算((2^{2...}-k))(2^{2...}),只不过模数由(p)变成(varphi(q))。当模数(p)变成1的时候,我们就遇到了边界——不管里面式子如何,模1都是0,直接返回0即可。考虑递归的层数:除了第一次调用的(p)可能是奇数之外,往下递归的(p)几乎都是偶数((varphi(x),xge3)都是偶数),(varphi(q))相对于(p)大概会减少一倍。直到(p=1)时,层数不会太多,dalao说是(O(log^2p))。
      
      所以就直接递归计算了。实现上,如果先用线性筛筛出所有的(varphi),太慢。每次调用(varphi)时直接(O(sqrt n))计算反而更加快。这两种方法,是稳定300ms和6ms的差距......
      
      
      

    Code

      

    #include <cstdio>
    using namespace std;
    const int S=10000001;
    inline int ksm(int x,int y,int MOD){
    	int res=1;
    	for(;y;x=1LL*x*x%MOD,y>>=1)
    		if(y&1) res=1LL*res*x%MOD;
    	return res;
    }
    int getPhi(int x){
    	int res=x;
    	for(int i=2;i*i<=x;i++){
    		if(!(x%i)) res-=res/i;
    		while(!(x%i)) x/=i;
    	}
    	if(x!=1) res-=res/x;
    	return res;
    }
    int calc(int p){
    	if(p==1) return 0;
    	int k=0,q=p;
    	while(!(q&1)) k++,q>>=1;
    	int phiq=getPhi(q);
    	int mi=(calc(phiq)-k)%phiq;
    	if(mi<0) mi+=phiq;	
    	return 1LL*ksm(2,mi,q)*ksm(2,k,p)%p;
    }
    int main(){
    	int T,p;
    	scanf("%d",&T);
    	while(T--){
    		scanf("%d",&p);
    		printf("%d
    ",calc(p));
    	}
    	return 0;
    }
    
  • 相关阅读:
    输出任意实数
    字谜游戏
    选择问题
    Spark Streaming揭秘 Day4-事务一致性(Exactly one)
    Spark Streaming揭秘 Day3-运行基石(JobScheduler)大揭秘
    Spark Streaming揭秘 Day2-五大核心特征
    Spark Streaming揭秘 Day1-三大谜团
    深度学习在美团搜索广告排序的应用实践
    美团外卖客户端高可用建设体系
    大众点评账号业务高可用进阶之路
  • 原文地址:https://www.cnblogs.com/RogerDTZ/p/9210601.html
Copyright © 2020-2023  润新知