zoukankan      html  css  js  c++  java
  • 【题解】古代猪文 [SDOI2010] [BZOJ1951] [P2480]

    【题解】古代猪文 [SDOI2010] [BZOJ1951] [P2480]


    在那山的那边海的那边有一群小肥猪。他们活泼又聪明,他们调皮又灵敏。他们自由自在生活在那绿色的大草坪,他们善良勇敢相互都关心……”——选自猪王国民歌


    【题目描述】

    (()仅供观赏())

    猪王国的文明源远流长,博大精深。

    (iPig)在大肥猪学校图书馆中查阅资料,得知远古时期猪文文字总个数为(N)。当然,一种语言如果字数很多,字典也相应会很大。当时的猪王国国王考虑到如果修一本字典,规模有可能远远超过康熙字典,花费的猪力、物力将难以估量。故考虑再三没有进行这一项劳猪伤财之举。当然,猪王国的文字后来随着历史变迁逐渐进行了简化,去掉了一些不常用的字。

    (iPig)打算研究古时某个朝代的猪文文字。根据相关文献记载,那个朝代流传的猪文文字恰好为远古时期的(k)分之一,其中(k)(N)的一个正约数(可以是(1)(N))。不过具体是哪(k)分之一,以及(k)是多少,由于历史过于久远,已经无从考证了。

    (iPig)觉得只要符合文献,每一种能整除(N)(k)都是有可能的。他打算考虑到所有可能的k。显然当(k)等于某个定值时,该朝的猪文文字个数为(N / k)。然而从(N)个文字中保留下(N / k)个的情况也是相当多的。(iPig)预计,如果所有可能的k的所有情况数加起来为(P)的话,那么他研究古代文字的代价将会是(G)(P)次方。

    现在他想知道猪王国研究古代文字的代价是多少。由于(iPig)觉得这个数字可能是天文数字,所以你只需要告诉他答案除以(999911659)的余数就可以了。

    【真正的题目描述(人话)】

    给定 (n)(G) (,)(:) (G^{sum_{d|n}C_n^d}mod 999911659)

    【数据规模】

    (10\%) (1 leqslant N leqslant 50)

    (20\%) (1 leqslant N leqslant 1000)

    (40\%) (1 leqslant N leqslant 100000)

    (100\%) (1 leqslant N leqslant 1000000000,1 leqslant G leqslant 1000000000)


    【分析】

    看到上面这个式子,很容易想到暴力解法:枚举 (n) 的所有正约数 (d),分别求出 (C_n^d) 并累加答案,最后对 (999911659) 取模,如果你的目的不是 (pian) (fen) 而是 (AC),并且甘愿屈服于 (TLE)(MLE)(RE) 的统治,那么就大胆的去尝试吧!

    【正解】

    (【Key) (1】):欧拉定理的推论

    (什么?你说你不知道欧拉定理?(O__O "…))

    公式:(a^b equiv a^{bmod varphi(P)}(mod P)) (,) (gcd(a,P)=1)

    在本题中 (P=999911659) 是一个质数(不要问我是怎么知道的),所以对任意 (a) 均满足 (gcd(a,P)=1),且有 (varphi(P)=P-1)

    根据公式可得 (G^{sum_{d|n} C_n^d}=G^{sum_{d|n}C_n^dmod 999911658}(mod 999911659))

    因此本题关键是计算 (sum_{d|n}C_n^dmod 999911658)

    (【Key) (2】)(Lucas) 定理

    公式: (C_n^m=C_{nmod P}^{mmod P}*C_{n/P}^{m/P}(mod P))

    求组合数并要求取模,一看就知道要用 (Lucas) 定理,这里不多说。

    但是......
    模数不为质数并且数据规模简直无敌,仍然会被 (TLE,MLE,RE)摁在地上摩擦
    于是我们需要将这个大巨无霸问题分解成小蒟蒻问题。

    (【Key) (3】)(Square) (Free) (Number)

    (999911658) 分解质因数,得到 (999911658=2*3*4679*35617) ,它的所有质因子的指数都为 (1) ,这一类数被称作 (Square) (Free) (Number)
    (Q:) 这样做有什么用呢?
    (A:) 马上就会提到。。。

    (【Key) (4】)(CRT()中国剩余定理())

    首先用 (Lucas) 定理分别求出 (sum_{d|n}C_n^d)(2,3,4679,35617) 这四个质数取模后的值,记为 (a_1,a_2,a_3,a_4) ,然后用中国剩余定理解一个线性同余方程组:

    (egin{cases}xmod 2=a_1\xmod 3=a_2\xmod 4679=a_3\xmod 35617=a_4end{cases})

    于是我们就得到了 (sum_{d|n}C_n^dmod 999911658) 的一个最小非负整数解 (x),最后再用一次快速幂计算 (G^x)就是答案。

    (【Code】)
    #pragma GCC optimize(3,"Ofast","inline")
    #pragma GCC optimize(2)
    #include<cstdio>
    #define LL long long
    #define Re register LL
    const int PP=35617,P=999911658;
    LL x,y,i,j,n,G,fu,ans,a[5],jc[PP+3]={1},mod[5]={0,2,3,4679,35617};char c;
    inline void in(Re &x){//【快读】自己动手,丰衣足食 
        fu=x=0;c=getchar();
        while(c<'0'||c>'9')fu|=c=='-',c=getchar();
        while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+(c^48),c=getchar();
        x=fu?-x:x;
    }
    inline LL mi(Re x,Re k,Re P){//【快速幂】如果你非要写龟速乘我也拦不住你 
        Re s=1;
        while(k){
            if(k&1)(s*=x)%=P;
            (x*=x)%=P,k>>=1;
        }
        return s;
    }
    inline LL Lucas(Re m,Re n,Re p){//【Lucas定理】 
        if(n<m)return 0;
        if(n<p)return jc[n]*mi(jc[m],p-2,p)%p*mi(jc[n-m],p-2,p)%p;
        return Lucas(m/p,n/p,p)*Lucas(m%p,n%p,p)%p;
    }
    inline void init(Re P){for(Re i=1;i<=P;++i)jc[i]=jc[i-1]*i%P;}//【预处理阶乘】
    //对于四个模数都要预处理出不同的阶乘
    inline void exgcd(Re &x,Re &y,Re a,Re b){//【扩欧】解线性同余方程 
        if(!b){x=1,y=0;return;}
        exgcd(x,y,b,a%b);Re X=x;
        x=y,y=X-a/b*y;
    }
    int main(){
        in(n),in(G);
        if(G%(P+1)==0){printf("0");return 0;}//如果定义P=999911658,注意这里要加 1 
        //当 G 为 999911659 的倍数时,直接特判结束 
        for(i=1;i<=4;++i){//【分解质因数】 
            init(mod[i]);//【初始化阶乘】 
            for(j=1;j*j<n;++j)
                if(n%j==0)(((a[i]+=Lucas(j,n,mod[i]))%=mod[i])+=Lucas(n/j,n,mod[i]))%=mod[i];
               //累加组合数并取模 
            if(j*j==n)(a[i]+=Lucas(j,n,mod[i]))%=mod[i];
        }
        for(i=1;i<=4;++i){//【中国剩余定理】跑一遍 CRT 解方程组 
            Re M=P/mod[i];exgcd(x,y,M,mod[i]);
            (x+=mod[i])%=mod[i];(ans+=M*x%P*a[i]%P)%=P;
        }
        printf("%lld",mi(G,(ans+P)%P,P+1));//加 1..... 
    }
    

    【题外话】

    善良无比的 わたし 提供了本题的测试数据(98u9)(QAQ)


  • 相关阅读:
    (6)Lua 模块与包
    (3)Lua 迭代器与迭代函数
    (二)miller指导查看主控板寄存器操作
    (一)mtg3000常见操作
    (三)NAND flash和NOR flash的区别详解
    (八)shell中的循环结构
    (七)shell编程学习
    (六)动手写第一个shell
    (五)uboot移植补基础之shell
    (四)ubuntu学习前传—uboot中对Flash和DDR的管理
  • 原文地址:https://www.cnblogs.com/Xing-Ling/p/10745325.html
Copyright © 2011-2022 走看看