C. Alternating Sum(数论——等比数列公式与变换)

  • 题目链接:http://codeforces.com/contest/964/problem/C
  • 题意:给你四个整数和一个字符串,求数列和:这里写图片描述 膜1e9+9的正数结果
    • n——数列项数从第0项到第n项
    • a、b如上式子
    • k——数列的周期,k可整除n+1
    • 字符串s,表示项数的正负
  • 算法:数论——等比数列
  • 思维素材:需要得到正数结果时,最好把公式化成方便得到正数的形式

#include <bits/stdc++.h>
#define pi acos(-1)
#define fastcin ios::base_sync_with_stdio(false);cin.tie(NULL);cout.tie(NULL);
using namespace std;
typedef long long LL;
typedef pair<int,int> Pii;
const int INF = 0x3f3f3f3f;
const int maxn = 1e5+10;
const int mod = 1e9 + 9;

void exgcd(LL a, LL b, LL &x, LL &y)    //拓展欧几里得算法
{
    if(!b) x = 1, y = 0;
    else
    {
        exgcd(b, a % b, y, x);
        y -= x * (a / b);
    }
}

LL inv(LL a, LL b)   //求a对b取模的逆元
{
    LL x, y;
    exgcd(a, b, x, y);
    return (x + b) % b;
}

LL fpow(LL a, LL n, LL p)    //快速幂 a^n % p
{
    LL ans = 1;
    while(n)
    {
        if(n & 1) ans = ans * a % p;
        a = a * a % p;
        n >>= 1;
    }
    return ans;
}

int main()
{
    LL n, a, b, k;
    string s;
    scanf("%I64d%I64d%I64d%I64d", &n, &a, &b, &k);
    cin >> s;
    LL INVa = inv(a, mod);
    LL q = fpow(INVa*b%mod, k, mod);
    LL tmp=0;
    if(q==1) tmp = (n+1)/k;
    else {
        tmp = ( tmp+ (fpow(q, (n+1)/k, mod)-1) * inv(q-1, mod) )%mod;
    }
    //cout << tmp << endl;
    LL ans=0;
    for(int i=0; i<k; i++){
        LL sign = (s[i]=='+'?1:-1);
        ans = ( ans + fpow(a, n-i, mod)*fpow(b, i, mod)%mod*tmp%mod*sign )%mod;
    }
    printf("%I64d\n", (ans+mod)%mod);
}

猜你喜欢

转载自blog.csdn.net/qq_37352710/article/details/80139210