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

题目大意:

看一下样例就明白了

基本思路:

题目中明确提到k为一个周期,稍作思考,把k项看作一项,然后发现这是个等比数列,q=(b/a)^k,

然后重点就是怎样处理等比数列求和表达式中的除法,这个时候就要用到逆元,因为1e9+9是素数,

所以直接用费马小定理求逆元就好了,说到这个,可以学一下卢卡斯定理,这个比较有用处,然后需要注意

两点:

1)快速幂a的每次乘方里面都要%mod,这个到底是为什么我也不知道,难道不是只在外面取模一次就好了吗

2)最后判断条件是t2是否等于0,而不是a是否等于b,难道不是等价的吗?为什么会这样?

代码如下:

#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;
}

  

 

posted @ 2018-04-19 09:29  愿~得偿所愿,不负时光  阅读(362)  评论(0编辑  收藏  举报