Codeforces 964 C. Alternating Sum (求和+逆元)

Description

You are given two integers a and b. Moreover, you are given a sequence s0,s1,…,sn. All values in s are integers 1 or −1. It’s known that sequence is k-periodic and k divides n+1. In other words, for each k≤i≤n it’s satisfied that si=sik. s i = s i − k .
Find out the non-negative remainder of division of ni=0sianibi ∑ i = 0 n s i a n − i b i by 109+9.
Note that the modulo is unusual!

Input

The first line contains four integers n,a,b and k(1≤n≤109,1≤a,b≤109,1≤k≤105).
The second line contains a sequence of length k consisting of characters ‘+’ and ‘-‘.
If the i-th character (0-indexed) is ‘+’, then si=1, otherwise si=−1.
Note that only the first k members of the sequence are given, the rest can be obtained using the periodicity property.

Output

Output a single integer — value of given expression modulo 109+9. 10 9 + 9.

Examples

input
2 2 3 3
+-+
output
7
input
4 1 5 1
-
output
999999228

题目描述

ni=0sianibi ∑ i = 0 n s i a n − i b i ,其中si由给定的符号字符串确定,若对应位置为‘+’,则si=1,否则si=-1,字符串的长度为k,当i大于k时,从头循环获取对应位置.

解题思路

首先看到k的范围是1e5,便可以考虑从这里入手去求解,当n>k时,可以发现每k个连续的数之间成比例,且比值为 bkak b k a k ,这样便可以构成一个公比为 bkak b k a k 的,项数为num=(n+1)/k 的等比数列,从头循环一遍k便可得出首项,然后等比数列求和.剩余的(n+1)-num*k即无法构成等比数列的数再单独遍历求和即可.
Ps:求逆元是肯定的,但是要注意判断公比的逆元是否为1.不要傻乎乎的在求逆元之前判断(ಥ﹏ಥ)C题又没达成(ಥ﹏ಥ)

代码实现

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn =1e5+7;
const ll mod=1e9+9;
#define IO ios::sync_with_stdio(false);\
cin.tie(0);\
cout.tie(0);
char str[maxn];
ll quick_pow(ll a,ll b)
{
    ll ans=1;
    while(b)
    {
        if(b%2)
            ans=(ans*a)%mod;
        a=(a*a)%mod;
        b/=2;
    }
    return ans;
}
int main()
{
    IO;
    ll n,a,b,k;
    cin>>n>>a>>b>>k>>str;
    ll ans=0;
    ll res=0;
    ll x=quick_pow(a,n),xx=quick_pow(a,mod-2),xxx=1;  //a^n,a的逆元
    ll y=quick_pow(b,n),yy=quick_pow(b,mod-2),yyy=1;  //同上
    int mark;
    for(int i=0; i<k; i++)      //前k个的和
    {
        if(str[i]=='+') mark=1;
        else mark=-1;
        res=(res+mark*x*yyy)%mod;
        x=(x*xx)%mod;
        yyy=(yyy*b)%mod;
    }
    ll num=(n+1)/k;                              //该等比数列含有num个项
    ll divide=quick_pow(quick_pow(a,k),mod-2);   //a^k的逆元
    ll mul=quick_pow(b,k);                       //b^k
    ll q=mul*divide%mod;                         //公比
    if(q==1)
        ans=(num*res)%mod;
    else
        ans=(res*((1-quick_pow(q,num))%mod)%mod*quick_pow(1-q,mod-2)%mod+mod)%mod;
    num=(n+1)-num*k;                             //除去可构成等比数列之后的剩余项
    ll id=num-1;                                 //由后向前加和
    res=0;
    for(ll i=0; i<num; i++)
    {
        if(str[id]=='+') mark=1;
        else mark=-1;
        res=(res+mark*y*xxx)%mod;
        y=(y*yy)%mod;
        xxx=(xxx*a)%mod;
        id--;
    }
    ans=((ans+res)%mod+mod)%mod;
    cout<<ans<<endl;
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值