Codeforces 963E Alternating Sum 等比數列+逆元

題目大意:ios

看一下樣例就明白了spa

基本思路:code

題目中明確提到k爲一個週期,稍做思考,把k項看做一項,而後發現這是個等比數列,q=(b/a)^k,blog

而後重點就是怎樣處理等比數列求和表達式中的除法,這個時候就要用到逆元,由於1e9+9是素數,ci

因此直接用費馬小定理求逆元就行了,說到這個,能夠學一下盧卡斯定理,這個比較有用處,而後須要注意string

兩點:it

1)快速冪a的每次乘方里面都要%mod,這個究竟是爲何我也不知道,難道不是隻在外面取模一次就行了嗎io

2)最後判斷條件是t2是否等於0,而不是a是否等於b,難道不是等價的嗎?爲何會這樣?class

代碼以下:stream

#include<cstdio>
#include<cmath>
#include<cstring>
#include<iostream>
#include<string>
#include<algorithm>
#include<queue>
#include<vector>

using namespace std;

typedef long long ll;
typedef long long LL;
typedef pair<int,int> pii;
const int inf = 0x3f3f3f3f;
const int maxn = 100000+10;
const ll mod = 1e9+9;

char s[maxn];
ll qpow(int a,int b){
    ll res=1;
    while(b){
        if(b&1) res=(res*a)%mod;
        a=(a%mod*a%mod)%mod;
        b>>=1;
    }
    return res%mod;
}
int main(){
    int n,a,b,k;
    scanf("%d%d%d%d",&n,&a,&b,&k);
    scanf("%s", s);
    int len = strlen(s);
    LL ans = 0;
    LL tmp, cir = 0;
    for(int i = 0; i < len; i++){
        tmp = qpow(a,n-i) * qpow(b,i) % mod;
        if(s[i] == '+') {
            cir += tmp;
            cir %= mod;
        }
        else {
            cir -= tmp;
            if(cir < 0) cir += mod;
            cir %= mod;
        }
    }
    int time = (n+1) / len;
    int lf = n+1 - len*time;
    int be = len*time;
    for(int i = 0; be <= n; i++, be++){
        tmp = qpow(a,n-be) * qpow(b,be) % mod;
        if(s[i] == '+') {
            ans += tmp;
            ans %= mod;
        }
        else {
            ans -= tmp;
            if(ans < 0) ans += mod;
            ans %= mod;
        }
    }
    ll t1=(qpow(a,len*time)-qpow(b,len*time))%mod;
    if(t1<0) t1+=mod;
    ll t2=(qpow(a,k*time)-(qpow(a,k*(time-1))*qpow(b,k)%mod))%mod;
    if(t2<0) t2+=mod;
    ll t3=t1*qpow(t2,mod-2)%mod;
    if(t2==0){
        printf("%I64d\n",(ans+cir*time%mod)%mod);
    }else{
        printf("%I64d\n",(ans+cir*t3%mod)%mod);
    }
    return 0;
}
相關文章
相關標籤/搜索