zoukankan      html  css  js  c++  java
  • BZOJ 3884 上帝与集合的正确用法

    Description

    根据一些书上的记载,上帝的一次失败的创世经历是这样的:
    第一天, 上帝创造了一个世界的基本元素,称做“元”。
    第二天, 上帝创造了一个新的元素,称作“(alpha)”。“(alpha)被定义为“元”构成的集合。容易发现,一共有两种不同的“(alpha)”。
    第三天, 上帝又创造了一个新的元素,称作“(eta)”。“(eta)”被定义为“(alpha)”构成的集合。容易发现,一共有四种不同的“(eta)”。
    第四天, 上帝创造了新的元素“(gamma)”,“(gamma)”被定义为“(eta)”的集合。显然,一共会有(16)种不同的“(gamma)”。
    如果按照这样下去,上帝创造的第四种元素将会有65536种,第五种元素将会有(2^{65536})种。这将会是一个天文数字。
    然而,上帝并没有预料到元素种类数的增长是如此的迅速。他想要让世界的元素丰富起来,因此,日复一日,年复一年,他重复地创造着新的元素……
    然而不久,当上帝创造出最后一种元素“( heta)”时,他发现这世界的元素实在是太多了,以致于世界的容量不足,无法承受。因此在这一天,上帝毁灭了世界。
    至今,上帝仍记得那次失败的创世经历,现在他想问问你,他最后一次创造的元素“( heta)”一共有多少种?
    上帝觉得这个数字可能过于巨大而无法表示出来,因此你只需要回答这个数对(p)取模后的值即可。
    你可以认为上帝从“(alpha)”到“( heta)”一共创造了(10^{9})次元素,或(10^{18})次,或者干脆(infty)次。
    一句话题意:

    Input

    接下来(T)行,每行一个正整数(p),代表你需要取模的值

    Output

    (T)行,每行一个正整数,为答案对(p)取模后的值

    Sample Input

    3
    2
    3
    6

    Sample Output

    0
    1
    4

    HINT

    对于(100\%)的数据,(T le 1000,p le 10^{7})

    对于此题一个重要的定理:
    (b ge phi(c))

    [a^{b} equiv a^{b ; mod ; phi(c)+phi(c)}(mod ; c) ]

    因为指数为无限项,恒有(b ge phi(c)),所以根据这个定理,我们就可以做题了。

    [f(c)=2^{2^{2^{2^{...}}}} mod ; c ]

    则有

    [f(c)=2^{2^{2^{2^{...}}} ; mod ; phi(c) + phi(c)}; mod ; c=2^{f(phi(c))+phi(c)} ]

    递归边界:

    [f(1)=0 ]

    所以这题就可以做了。
    ~~我深深感觉到了自己数学的弱菜,只知道定理却不会用。恶补数学ing~~

    #include<cstdio>
    #include<cstdlib>
    #include<map>
    using namespace std;
    
    typedef long long ll;
    map <int,int> M;
    
    inline ll qsm(ll a,ll b,ll c)
    {
    	ll ret = 1;
    	for (;b;b >>= 1,(a *= a)%=c)
    		if (b & 1) (ret *= a)%=c;
    	return ret;
    }
    
    inline ll phi(ll n)
    {
    	ll ret = n;
    	for (ll i = 2;i*i <= n;++i)
    	{
    		if (n % i == 0)
    		{
    			while (n % i == 0) n /= i;
    			ret /= i; ret *= i-1;
    		}
    	}
    	if (n > 1) ret /= n,ret *= n-1;
    	return ret;
    }
    
    inline ll calc(ll n)
    {
    	if (M.count(n)) return M[n];
    	ll p = phi(n);
    	return M[n] = qsm(2,calc(p)+p,n);
    }
    
    int main()
    {
    	freopen("3884.in","r",stdin);
    	freopen("3884.out","w",stdout);
    	ll T; scanf("%lld",&T);
    	M[1] = 0;
    	while (T--)
    	{
    		ll n; scanf("%lld",&n);
    		printf("%lld
    ",calc(n));
    	}
    	fclose(stdin); fclose(stdout);
    	return 0;
    }
    
  • 相关阅读:
    三个心态做人做学问 沧海
    成功走职场要找准自己的"快捷键" 沧海
    免费离线下载 拂晓风起
    Hibernate 获取某个表全部记录时 奇怪现象 (重复出现某个记录) 拂晓风起
    无法读取mdb 如果连接不了ACCESS mdb文件,就尝试安装MDAC 拂晓风起
    Netbeans 使用 Hibernate 逆向工程 生成hbm和pojo 拂晓风起
    如何点击单选框 radio 后面的文字,选中单选框 拂晓风起
    Java 连接access 使用access文件 不用配置 拂晓风起
    mysql下如何执行sql脚本 拂晓风起
    Hibernate配置access Hibernate 连接 access 拂晓风起
  • 原文地址:https://www.cnblogs.com/mmlz/p/4308314.html
Copyright © 2011-2022 走看看