ZOJ 3774 二次剩余

Posted ( m Lweleth)

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ZOJ 3774 二次剩余相关的知识,希望对你有一定的参考价值。

LINK

题意:简单粗暴,求菲波那契数列每个数的m次的前n项和模1e9+7

思路:斐波那契通项式技术分享, 注意到有很多根号5,求二次剩余为5模1e9+7的解,显然我们可以直接找一个(383008016),然后拿来替代根号5,然后优化下,把中括号中共轭的两部分预处理下,然后由于是外部的一个指数m,从1枚举到m,来求二项式定理的每项系数,再用个逆元就好了。人家的校赛题(

 

/** @Date    : 2017-03-18-15.39
  * @Author  : Lweleth ([email protected])
  * @Link    : https://github.com/
  * @Version :
  */
#include<bits/stdc++.h>
#define LL long long
#define PII pair<int ,int>
#define MP(x, y) make_pair((x),(y))
#define fi first
#define se second
#define PB(x) push_back((x))
#define MMG(x) memset((x), -1,sizeof(x))
#define MMF(x) memset((x),0,sizeof(x))
#define MMI(x) memset((x), INF, sizeof(x))
using namespace std;

const int INF = 0x3f3f3f3f;
const int N = 1e5+20;
const double eps = 1e-8;
const LL mod = 1e9 + 9;
const LL trem = 383008016;
LL fac[N], le[N], ri[N];

LL fpow(LL a, LL n)
{
    LL res = 1;
    while(n > 0)
    {
        if(n & 1)
            res = res * a % mod;
        a = a * a % mod;
        n >>= 1;
    }
    return res;
}

LL Inv(LL x)
{
    return fpow(x, mod - 2);
}

void init()
{
    LL tinv = Inv(2);

    fac[0] = 1;
    le[0] = ri[0] = 1;
    LL l = ((1 + trem + mod)%mod) * tinv % mod;
    LL r = ((1 - trem + mod)%mod) * tinv % mod;
    for(LL i = 1; i < N; i++)
        fac[i] = fac[i - 1] * i % mod;
    for(int i = 1; i < N; i++)
    {
        le[i] = le[i - 1] * l % mod;
        ri[i] = ri[i - 1] * r % mod;
        //cout << le[i] <<" " <<  ri[i] << endl;
    }
}
int T;
LL n, k;
int main()
{
    init();
    cin >> T;
    while(T--)
    {
        scanf("%lld%lld", &n, &k);
        LL ans = 0;
        for(int i = 0; i <= k; i++)
        {
            LL flag = 1;
            if((k - i) % 2)
                flag = -1;
            LL t = le[i] * ri[k - i] % mod;
            LL d = fac[k - i] * fac[i] % mod;
            LL c = fac[k] * Inv(d) % mod;
            LL x = (t * (1 - fpow(t, n)) % mod) * Inv(1 - t) % mod;
            if(t == 1)
                x = n % mod;
            ans = (ans + flag * c * x ) % mod;
            ans = (ans + mod) % mod;
            //cout << t << endl;
        }
        ans = (ans * fpow(Inv(trem) % mod, k) + mod) % mod;
        printf("%lld\n", ans);
    }
    return 0;
}

以上是关于ZOJ 3774 二次剩余的主要内容,如果未能解决你的问题,请参考以下文章

在下面的代码片段中的剩余 ='passthrough' 处的代码中出现语法错误

二次剩余&&Cipolla

[贪心] aw3774. 亮灯时长(思维+后缀和+代码细节+CF1000B)

二次剩余

hdu 3589(二次剩余+雅可比符号)

二次剩余基础