C. Alternating Sum
题意:给出n,a,b,k,第二行给出长度为k一个字符串s,s[i]='+'或者s[i]='-',求 n∑i=0sian−ibi∑i=0nsian−ibi 在模109+9109+9
下的值,其中s[i]=s[i%k];
思路:先将字符串s的长度进行扩展到大于int(1e4)的k倍长度的字符串s,将求和的n+1个数分割成(n+1)/k份,剩下的部分再暴力求解。(ps:如果(n+1)%k==0,应该分割成((n+1)/k-1)份,剩下的k份单独求)其中(n+1)/k份是等比数列,记住,不需要用等比数列的求和公式求(因为需要逆元),直接通过比例变换即可求出。
举个栗子:
n=9,a=2,b=3,k=2,s="++";
m=(n+1)/k=5;
因为(n+1)%k==0;
所以分割成m=4份,剩下的2项单独处理。
求一个k份的大小是tmp=2^2*3^0+2^1*3^1;
则第一个k份的大小为2^9*3^0+2^8*3^1=2^7*3^0*tmp;
第二个k份的大小为2^7*3^2+2^6*3^3=2^5*3^2*tmp;
第三个k份的大小为2^5*3^4+2^4*3^5=2^3*3^4*tmp;
第四个k份的大小为2^3*3^6+2^2*3^7=2^3*3^4*tmp;
剩下的2^1*3^8+2^0*3^9单独处理。
#include<bits/stdc++.h>
using namespace std;
const int maxn=1000000+10;
const int mod=int(1e9)+9;
#define ll long long
ll quick_pow(ll base,ll n) {
ll ans=1;
while(n) {
if(n&1)
ans=ans*base%mod;
base=base*base%mod;
n>>=1;
}
return ans%mod;
}
char str[maxn];
int main() {
int n,a,b,k;
scanf("%d %d %d %d",&n,&a,&b,&k);
scanf("%s",str);
while(k<int(1e4)) {
for(int i=0; i<k; i++)
str[i+k]=str[i];
k<<=1;
}
ll ans=0;
int m=(n+1)/k;
ll st=n;
ll ed=0;
if(m>0) {
ll tmp=0;
if(st-k>0) {
st=st-k;
for(int i=0; i<k; i++) {
if(str[i]=='+')
tmp=(tmp+quick_pow(a,k-i)*quick_pow(b,i)%mod+mod)%mod;
else
tmp=(tmp-quick_pow(a,k-i)*quick_pow(b,i)%mod+mod)%mod;
}
while(st>0) {
ans=(ans+(quick_pow(a,st)*quick_pow(b,ed)%mod)*tmp%mod+mod)%mod;
st-=k;
ed+=k;
if(st<=0) {
st+=k;
ed-=k;
break;
}
}
}
}
ll sum=0;
for(int i=st; i>=0; i--) {
if(str[st-i]=='+')
sum=(sum+quick_pow(a,i)*quick_pow(b,n-i)%mod+mod)%mod;
else
sum=(sum-quick_pow(a,i)*quick_pow(b,n-i)%mod+mod)%mod;
}
ans=(ans+sum+mod)%mod;
printf("%lld\n",ans);
return 0;
}