51nod 3038 数列求和

题目链接

题意:
给定两个数 n n n k k k,求 ∑ i = 1 n i k   m o d   10007 \sum_{i=1}^ni^k\ mod\ 10007 i=1nik mod 10007的值

题解:
容易发现直接暴力枚举的时间复杂度是 O ( n l o g n ) O(nlogn) O(nlogn),而 n n n的数据范围比较大,因此暴力不行。
我们可以考虑到,这里的模数10007比较小,因此,我们可以从每个数模10007的余数下手。利用这个同余,我们发现 1 k , 1000 8 k , 2001 5 k , … % 10007 1^k,10008^k,20015^k,\dots\%10007 1k,10008k,20015k,%10007的值是相等的。可以发现,每隔10007个数就会出现一个同余的数,可以得到证明。因此,我们这里可以直接枚举余数,然后找出每个余数出现次数即可得到最后的答案。

实现细节见代码:

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

ll qpow(ll a, ll b) {
	ll ans = 1;
	while (b) {
		if (b & 1) {
			ans = (ans * a) % 10007;
		}
		a = (a * a) % 10007;
		b >>= 1;
	}
	return ans;
}
int main() 
{
	ios::sync_with_stdio(false);
	cin.tie(0), cout.tie(0);
	int t;
	cin >> t;
	while (t--) {
		ll n, k;
		cin >> n >> k;
		ll ans = 0;
		for (ll i = 1; i <= min(n, (ll)10007); i++) { // 枚举可能的余数
			ans = (ans + qpow(i, k) * ((n - i) / (ll)10007 + 1)) % 10007; // 找到该余数对应的出现次数
		}
		cout << ans << endl;
	}
    return 0;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值