洛谷P1630 求和(同余 + 快速幂)

题目链接

暴力:
计算每个数的b次幂——O(b),将算得的数加和 ——O(a),N组样例O(N),所以暴力解法的时间复杂度为
O(a × b × n)。即1e9 * 1e9 * 1e2 = 10^20,大概要大概要 10^12s,也就是大概31710年吧(雾)。

我们开始进行优化,首先快速幂可以很优秀的优化掉乘法的过程,将O(b)的复杂度优化为O(log b)。
优化之后时间复杂度为O(a * log b * N),大概是 1e12,也就是1000s,还是很大呜呜呜0w0。

int ksm(int a, int b, int mod)  //快速幂
{
	if(b == 1) return a;
	if(b & 1) return a % mod * ksm(a, b - 1) % mod;
	else 
	{
		int x = ksm(a, b / 2) % mod;  
		return x * x % mod;
	}
}

可以发现即使快速幂能够极大程度的优化乘法的过程,但是我们的算法依然很慢很慢。

这里可以发现需要模的数字很小,仅仅1e4,所以我们可以从这个地方下手。我们可以发现对一个数a,都有 (a + 10000) % 10000 ≡ a % 10000,根据同余的性质,有(a + 10000)^b % 10000 ≡ a^b %10000。对于每个大于10000的数a,a^b和(a % 10000) ^ b相等,也就是说我们已经在之前计算1到10000内的数的b次幂的时候就已经计算过a^b。

但是我们需要注意,a是一个很大的数字,最大为1e9,会出现重复计算多次相同的值的情况。

例如,a为1e6 + 10,那么实际上我们计算1 ~ 10000的b次幂的加和需要计算三次,然后还需要加上1 ~ 10的b次幂的加和。

也就是说,我们最后需要的
得数是 add (1-10000) * (a / 10000)+ add (1 - a).

我们发现我们可以用一个数将1-10000的和记录下来,但是我们之后还需要计算 1 - a的和,实际上这个数字已经在我们之前计算1-10000的和的时候就计算过,所以我们可以用前缀和数组来记录这个数字,进行优化。
最后可以用O(1)的复杂度进行公式运算得出答案。

我们来看看现在的时间复杂度:
预处理复杂度:O(log b * 1e4 * N),
求解复杂度: O(1)。

所以总时间复杂度为1e6 ~ 1e7,接近1s,可以求解。

通过快速幂,同余和前缀和,我们将一个10 ^ 20的算法优化到了10 ^ 7!!!

AC代码:

#include<bits/stdc++.h>
#define ll long long
#define inf 0x3f3f3f30f
#define mod 10000
#define endl '\n'
#define IOS std::ios::sync_with_stdio(false);cin.tie(0)

using namespace std;

const int N = 1e4 + 10;

int sum[N];

int ksm(int a, int b)
{
	if(b == 1) return a;
	if(b & 1) return a % mod * ksm(a, b - 1) % mod;
	else  
	{
		int x = ksm(a, b / 2) % mod;
		return (x * x) % mod;
	}
}

void solve()
{
	int a, b;
	cin >> a >> b;
	for(int i = 1; i <= N; i ++)
		sum[i] = (sum[i - 1] % mod + ksm(i, b) % mod) % mod;
	cout << (a/10000 * qz[10000] + qz[a % 10000]) % mod << endl;
}

int main()
{
	IOS;
	int t;
	cin >> t;
	while(t --)
	{
		solve();
		memset(qz, 0, sizeof qz);
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值