求和
题目描述
求 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 N≤10, a , b ≤ 1 0 3 a,b \le 10^3 a,b≤103。
对于 100 % 100\% 100% 的数据, 1 ≤ N ≤ 100 1 \le N \le 100 1≤N≤100, 1 ≤ a , b ≤ 1 0 9 1 \le a,b \le 10^9 1≤a,b≤109。
这道题想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;
}