zoukankan      html  css  js  c++  java
  • 【bzoj1951】[Sdoi2010]古代猪文 费马小定理+Lucas定理+中国剩余定理

    题目描述

    求  $g^{sumlimits_{k|n}C_{n}^{frac nk}}mod 999911659$

    输入

    有且仅有一行:两个数N、G,用一个空格分开。

    输出

    有且仅有一行:一个数,表示答案除以999911659的余数。

    样例输入

    4 2

    样例输出

    2048


    题解

    费马小定理+Lucas定理+中国剩余定理

    首先由费马小定理$a^{p-1}equiv 1 (mod p)$,可以将模数转化到答案的指数上,即求$sumlimits_{k|n}C_{n}^{frac nk} mod 999911658 = sumlimits_{k|n}C_{n}^{k} mod 999911658$。

    然后直接$O(sqrt n)$枚举一对约数中较小的那个,直接计算即可。

    但这里有一个问题:减1以后模数不是质数。

    于是我们需要将其进行质因子分解:$999911658=2*3*4679*35617$,然后先使用Lucas定理算出$C_n^k$在模其质因子意义下的结果,然后再使用中国剩余定理合并模线性同余方程组即可。在求解时,由于一定有解,因此不需要判定解得合法性,直接求逆元除过去即可。

    时间复杂度$O(sqrt{n}log^2n)$

    注意本题的一个巨大坑点:当$a mod p=0$时费马小定理不成立(底数模意义下为0,指数不为0但模意义下为0时会计算为1,而实际上0的正整数次幂应该为0),因此需要特判这种情况。

    #include <cstdio>
    #define MOD 999911658
    typedef long long ll;
    const int mod[] = {2 , 3 , 4679 , 35617};
    ll fac[4][36000];
    inline ll pow(ll x , ll y , int mod)
    {
    	ll ans = 1;
    	while(y)
    	{
    		if(y & 1) ans = ans * x % mod;
    		x = x * x % mod , y >>= 1;
    	}
    	return ans;
    }
    ll calc(int n , int m , int p)
    {
    	if(n < m) return 0;
    	if(n < mod[p]) return fac[p][n] * pow(fac[p][m] , mod[p] - 2 , mod[p]) * pow(fac[p][n - m] , mod[p] - 2 , mod[p]) % mod[p];
    	return calc(n / mod[p] , m / mod[p] , p) * calc(n % mod[p] , m % mod[p] , p) % mod[p];
    }
    ll C(int n , int m)
    {
    	int i;
    	ll ans = 0;
    	for(i = 0 ; i < 4 ; i ++ )
    		ans = (ans + MOD / mod[i] * pow(MOD / mod[i] , mod[i] - 2 , mod[i]) % MOD * calc(n , m , i)) % MOD;
    	return ans;
    }
    int main()
    {
    	int n , g , i , j;
    	ll sum = 0;
    	scanf("%d%d" , &n , &g) , g %= MOD + 1;
    	if(!g)
    	{
    		puts("0");
    		return 0;
    	}
    	for(i = 0 ; i < 4 ; i ++ )
    	{
    		fac[i][0] = 1;
    		for(j = 1 ; j < mod[i] ; j ++ ) fac[i][j] = fac[i][j - 1] * j % mod[i];
    	}
    	for(i = 1 ; i * i <= n ; i ++ )
    	{
    		if(n % i == 0)
    		{
    			sum = (sum + C(n , i)) % MOD;
    			if(i * i != n) sum = (sum + C(n , n / i)) % MOD;
    		}
    	}
    	printf("%lld
    " , pow(g , sum , MOD + 1));
    	return 0;
    }
    

     

  • 相关阅读:
    [django]django models最佳实战
    [vue]模拟移动端三级路由: router-link位置体现router的灵活性
    [js]顶部导航和内容区布局
    [django]django查询最佳实战
    [vue]webpack使用样式
    [vue]webpack中使用组件
    [vue]组件的导入
    [django]django权限简单实验
    [django]前后端分离之JWT用户认证
    [django]drf知识点梳理-权限
  • 原文地址:https://www.cnblogs.com/GXZlegend/p/7661151.html
Copyright © 2011-2022 走看看