洛谷P1630 求和

求和

题目描述

1 b + 2 b + ⋯ + a b 1^b+2^b+\cdots + a^b 1b+2b++ab 的和除以 1 0 4 10^4 104 的余数。

输入格式

本题有多组数据。

第一行一个整数 N N N,表示共有 N N N 组测试数据。

对于每组数据,一行两个整数 a , b a,b a,b

输出格式

对于每组数据,一行一个整数,表示答案。

样例 #1

样例输入 #1

1
2 3

样例输出 #1

9

提示

对于 30 % 30\% 30% 的数据, N ≤ 10 N \le 10 N10 a , b ≤ 1 0 3 a,b \le 10^3 a,b103

对于 100 % 100\% 100% 的数据, 1 ≤ N ≤ 100 1 \le N \le 100 1N100 1 ≤ a , b ≤ 1 0 9 1 \le a,b \le 10^9 1a,b109

这道题想AC比较困难,原因有以下几点:
1:数据规模庞大,无符号长整数都存不下。
2:复杂度高,易超时。
接下来给大家看一份0分代码:

#include<bits/stdc++.h>
using namespace std;
const int MOD=1e4;
int main() {
	long long n;
	cin >> n;
	while(n--){
		long long a,b;
		cin >> a >> b;
		long long ans=0;
		for(int i=1;i<=a;i++){
			long long sum=(int)(pow(i,b))%MOD;
			ans=(ans+sum)%MOD;
		}
		cout << ans << endl;
	}
    return 0;
}

以上这份代码朴实无华,用的函数是pow,开的也是long long,可结果就有点不尽人意了。3WA,7TLE。为什么呢,因为数据过于庞大,long long存不下,返回的一个负数,结果肯定不对。
其次,复杂度是n*a是肯定要超时的。
那么就用到快速幂了。
接下来给大家看一份30分代码:

#include<bits/stdc++.h>
using namespace std;
const int MOD=1e4;
long long power(int a,int n){
	int ans=1;
	while(n){
		if(n%2){
			ans=(ans%MOD)*(a%MOD)%MOD;
		}
		a=(a%MOD)*(a%MOD)%MOD;
		n/=2;
	}
	return ans;
}
int main() {
	long long n;
	cin >> n;
	while(n--){
		long long a,b;
		cin >> a >> b;
		long long ans=0;
		for(int i=1;i<=a;i++){
			long long sum=(int)(power(i,b))%MOD;
			ans=(ans+sum)%MOD;
		}
		cout << ans << endl;
	}
    return 0;
}

这份代码虽然经过快速幂优化但超时任是不可免的。那还能怎么优化呢?点开标签看到数学,好开始打表,怎么打表,我们可已将它每一次sum进行输出,如下图。
打表代码:

#include<bits/stdc++.h>
using namespace std;
const int MOD=1e4;
long long power(int a,int n){
	int ans=1;
	while(n){
		if(n%2){
			ans=(ans%MOD)*(a%MOD)%MOD;
		}
		a=(a%MOD)*(a%MOD)%MOD;
		n/=2;
	}
	return ans;
}
int main() {
	long long n;
	cin >> n;
	while(n--){
		long long a,b;
		cin >> a >> b;
		long long ans=0;
		int cnt=0;
		for(int i=1;i<=a;i++){
			long long sum=(int)(power(i,b))%MOD;
			cout << sum << " ";
			cnt++;
			if(cnt%5==0){
				cout << endl;
				cnt=0;
			}
			ans=(ans+sum)%MOD;
		}
		cout << ans << endl;
	}
    return 0;
}

在这里插入图片描述
现在开始寻找重复部分,发现为5000个一循环,但是这个数只针对于b=2所以我们还得继续打表,经过漫长的打表过程,可以发现无论b是几,每个循环个数都是1e4的因数(不会因数的请回小学重造!)就意味每个1e4它都会循环。1e4一个循环,这正好是题目的模数,相当与我表白打了 我们可以先算出每个循环的和,再计算没有到达一个循环的部分 ,这样复杂度将大大减少,因为我们只需一个循环进行求和 ,再来一个循环求不到1e4的。具体如下。

AC代码:

#include<bits/stdc++.h>
using namespace std;
const int MOD=1e4;
long long power(int a,int n){
	int ans=1;
	while(n){
		if(n%2){
			ans=(ans%MOD)*(a%MOD)%MOD;
		}
		a=(a%MOD)*(a%MOD)%MOD;
		n/=2;
	}
	return ans;
}
int main(){
	long long n;
	cin >> n;
	while(n--){
		long long a,b;
		cin >> a >> b;
		long long ans=0;
		for(int i=1;i<=10000;i++){
			long long sum=(int)(power(i,b))%MOD;
			ans=(ans+sum)%MOD;
		}
		ans=a/10000*ans;
		for(int i=1;i<=a%MOD;i++){
			long long sum=(int)(power(i,b))%MOD;
			ans=(ans+sum)%MOD; 
		}
		cout << ans << endl;
	}
    return 0;
}
  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值