acwing545.Kickstart闹钟,等比数列求和,推公式

题目太长了,直接看原题链接吧。传送门
首先固定指数幂,假设当前 k k k为2。
那么单独考虑每一个 A [ i ] A[i] A[i]的贡献到底是多少,就以题目里的 [ 1 , 4 , 2 ] [1,4,2] [1,4,2]这个序列为例。
A [ 1 ] A[1] A[1]的贡献为 A [ 1 ] ∗ ( 1 2 + 1 2 + 1 2 ) = 3 ∗ A [ i ] ∗ ( 1 2 ) A[1]*(1^2+1^2+1^2)=3*A[i]*(1^2) A[1](12+12+12)=3A[i](12)
A [ 2 ] A[2] A[2]的贡献为 A [ 2 ] ∗ ( 1 2 + 2 2 + 1 2 + 2 2 ) = 2 ∗ A [ 2 ] ∗ ( 1 2 + 2 2 ) A[2]*(1^2+2^2+1^2+2^2)=2*A[2]*(1^2+2^2) A[2](12+22+12+22)=2A[2](12+22)
A [ 3 ] A[3] A[3]的贡献为 A [ 3 ] ∗ ( 1 2 + 2 2 + 3 2 ) = 1 ∗ A [ 3 ] ∗ ( 1 2 + 2 2 + 3 2 ) A[3]*(1^2+2^2+3^2)=1*A[3]*(1^2+2^2+3^2) A[3](12+22+32)=1A[3](12+22+32)
即对于幂次 m m m A [ i ] A[i] A[i]的贡献为 ( n − i + 1 ) ∗ A [ i ] ∗ ∑ j = 1 i j m (n-i+1)*A[i]*\sum_{j=1}^ij^m (ni+1)A[i]j=1ijm
那么对于从 1 ∼ k 1\sim k 1k的幂次, A [ i ] A[i] A[i]的贡献为 ( n − i + 1 ) ∗ A [ i ] ∗ ∑ j = 1 i ∑ m = 1 k j m (n-i+1)*A[i]*\sum_{j=1}^i\sum_{m=1}^kj^m (ni+1)A[i]j=1im=1kjm,现在的问题就是该怎么计算了。
∑ m = 1 k j m \sum_{m=1}^kj^m m=1kjm拎出来就是一个等比数列的求和, S [ i ] = ∑ j = 1 i ∑ m = 1 k j m S[i]=\sum_{j=1}^i\sum_{m=1}^kj^m S[i]=j=1im=1kjm这一堆就是 i i i个等比数列求和。
考虑 S [ i ] − S [ i − 1 ] = ∑ m = 1 k i m S[i]-S[i-1]=\sum_{m=1}^ki^m S[i]S[i1]=m=1kim,所以可以在从 i = 1 ∼ n i=1\sim n i=1n遍历时递推求解。

#include <bits/stdc++.h>
using namespace std;

typedef long long ll;

const int mod = 1e9 + 7;

int qpow(int x, int n) {
	int res = 1;
	while (n) {
		if (n&1) {
			res = (1LL*res*x) % mod;
		}
		x = (1LL*x*x) % mod;
		n >>= 1;
	}
	return res;
}

int inv(int x) {
	return qpow(x, mod-2);
}

int ratio_seq_sum(int a1, int n) {
	if (a1 == 1) return n;
	return ((1LL*a1*((qpow(a1, n)-1+mod)%mod))%mod * inv(a1-1)) % mod;
}

int main() {
	cin.tie(0);
	ios_base::sync_with_stdio(false);
	int t, tt = 0;
	cin >> t;
	while (t--) {
		int n, k, x1, y1, c, d, e1, e2, f;
		cin >> n >> k >> x1 >> y1 >> c >> d >> e1 >> e2 >> f;
		vector<int> A(n+1);
		for (int i = 1; i <= n; i++) {
			A[i] = (x1 + y1) % f;
			int px = x1, py = y1;
			x1 = (1LL*c*px + 1LL*d*py + e1) % f;
			y1 = (1LL*d*px + 1LL*c*py + e2) % f;
		}
		
		int sum = 0;
		int res = 0;
		for (int i = 1; i <= n; i++) {
			sum += ratio_seq_sum(i, k);
			sum %= mod;
			res = (1LL*res + (n-i+1)*1LL*A[i]%mod*sum%mod) % mod;
		}
		cout << "Case #" << ++tt << ": ";
		cout << res << endl;
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值