CF963A Alternating Sum

Alternating Sum

题目传送门

思路:这道题呀,需要涉及到两个数学知识,一是逆元,二是等比数列求和公式。

一:逆元

我们知道 mod 这个东西在题目中时常出现,他可以用于加法,减法,乘法,然而,对于除法,它就不符合了,假定x是a的逆元值,那么b/a%c=b*x%c,就把除法转换成乘法,从而可以运用同余定理,防止计算中的数爆炸,是不是非常的没有用 ,嗯~~~~。

那么怎么求出a的逆元值呢,根据费马小定理,(有兴趣可以证明一下哈),因为小编也没怎么看懂,所以直入主题,简单来说就是b/a % c=b* a ( c − 2 ) a^{(c-2)} a(c2) %c。(前提c是素数)

二:等比数列求和公式

这个高中会学,也比较简单,在小编的范围之内,还是给大家推导一下吧。
假设有个a数列为等比公式,也就是满足ai-1*q=ai (q为公比)

S n = a 1 + a 2 . . . . . + a n Sn=a_1+a_2.....+a_n Sn=a1+a2.....+an
Sn * q-Sn=a1 *q+a2 * q…+an * q-a1-a2-a3…-an
Sn * q-Sn=a1 *q+a2 * q…+an * q-a1-a1 * q-a2 * q…-an-1 * q
Sn(q-1)=an * q-a1
Sn(q-1)=a(n+1)-a1
Sn(q-1)=a1 * q^n-a1
Sn=a1(q^n-1)/(q-1)
当然,也可以这样写:Sn=a1(1-q^n)/(1-q)

知识搞定了,那么我们就可以做题了。
大家先看看题目,就会发现S数列长度是k的倍数。
那么我们可以知道S=S1,S2,S3,…,Sk+(S1+…+Sn)。
那么每一个值用下面这个式子来求和
现在我们可以看出对于ai和ai+k来说,他们存在着一定关系
那么带入下面这个式子 Si*A^(n-i)*B ^i
自己推导一下q就为(b/a)^k

有这些那不就加上个疯狂mod不就大功造成了吗?
上代码:

#include<iostream>
#include<cstdio>
#include<cmath> 
#define N 100001
#define ll long long
using namespace std;
const ll mod=1e9+9;
ll pow1(ll x, ll y){
	while(x<0)x+=mod;
	ll ret=1;
	while(y)
	{
		if(y&1)(ret*=x)%=mod;
		(x*=x)%=mod,y>>=1;
	}
	return ret;
}
ll n,a,b,k;
char f;
ll s,sum,a1,q,zs;
int main()
{
	scanf("%lld%lld%lld%lld\n",&n,&a,&b,&k);
	for(int i=0;i<k;i++)
	   {
	   	scanf("%1c",&f);
	   	if(f=='+') s=1;
	   	else s=mod-1;
	   	a1=((s%mod*pow1(a,n-i)%mod)%mod*pow1(b,i)%mod)%mod;
	   	q=pow1(b*pow1(a,mod-2)%mod,k)%mod;
	   	zs=(n+1)/k;
	   	if(q==1) sum=(sum+a1*zs%mod)%mod;
		else sum=(sum+a1*(pow1(q,zs)-1)%mod*pow1(q-1,mod-2)%mod)%mod;
	   }
	printf("%lld",sum);
    return 0;	
} 

如有不足之处,请多谅解,小编尽力改进。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值