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