LuoguP5686 [CSP-S2019 江西] 和积和 题解
题目
P5686 [CSP-S2019 江西] 和积和
题目背景
JXCSP-S T2
题目描述
给定两个下标从 \(1\) 到 \(n\) 编号的序列 \(a_i,b_i\),定义函数 \(S(l,r)(1\le l\le r\le n)\) 为:
请你求出下列式子的值:
由于答案可能很大,你只需要给出答案模 \(10^9+7\) 后的结果。
输入格式
第一行一个正整数 \(n\) 表示序列长度。
第二行 \(n\) 个正整数表示 \(a_i\)。
第三行 \(n\) 个正整数表示 \(b_i\)。
输出格式
仅一行一个整数表示答案模 \(10^9+7\) 后的结果。
输入输出样例 #1
输入 #1
3
2 3 4
3 4 5
输出 #1
244
输入输出样例 #2
输入 #2
5
11 22 33 44 55
12 34 56 78 90
输出 #2
201542
说明/提示
【数据范围】
对于 \(20\%\) 的数据:\(n\le 10\) , \(a_i,b_i\le 10\);
对于 \(40\%\) 的数据:\(n\le 200\) , \(a_i,b_i\le 100\);
对于 \(70\%\) 的数据:\(n\le 3000\) , \(a_i,b_i\le 10^5\);
对于 \(100\%\) 的数据:\(3\le n\le 5\times 10^5\) , \(1\le a_i,b_i\le 10^9\)。
分析&做题历程
一:
第一思路自然是直接暴力,通过循环\(l\),\(r\),每次计算\(S(l,r)\)即可
//此为解释原理代码,故没有%mod操作,但实际得写
ll ans = 0;
for(int i=1;i<=n;i++){
for(int j=i;j<=n;j++){
//计算S(l,r), 这里为S(i,j)
ll cnt1 = 0,cnt2 = 0;
for(int k=i;k<=j;k++){
cnt1 += a[k];
cnt2 += b[k];
}
ans += cnt1*cnt2;
}
}
cout<<ans;
\(提交后20pts\)
二:
第二则是用前缀和优化求\(S(l,r)\)的过程
前缀和知识(会的可跳过)
设\(suma_i\)为\(a_i\)的前缀和数组,\(sumb_i\)为\(b_i\)的前缀和数组
注:
故
开始
则:\(S(l,r)(1\le l\le r\le n)\)
所以有代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;//答案可能会超int,故开long long保险
const ll mod = 1e9+7;//模数mod
const int N = 5e5+10;//数组大小
int n;
ll tmp;
ll a[N],b[N];
ll ans;
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
cin>>n;
for(int i=1;i<=n;i++){
cin>>tmp;
a[i] = (tmp + a[i-1])%mod;//由于原数组并不会用到,直接用a数组表示原数组的前缀和数组
}
for(int i=1;i<=n;i++){
cin>>tmp;
b[i] = (tmp + b[i-1])%mod;//由于原数组并不会用到,直接用a数组表示原数组的前缀和数组
}
for(int i=1;i<=n;i++){
for(int j=i;j<=n;j++){
ans += (a[j]-a[i-1])*(b[j]-b[i-1])%mod;//优化操作
ans %= mod;
}
}
cout<<ans;
return 0;
}
\(提交后70pts,剩余都TLE\)
三:
\(由于是TLE,故还得优化,观察ans的式子\)
\(尝试展开式子优化\)
\(由于原数组没有用到,故用a_i直接表示suma_i,b_i直接表示sumb_i\)
\(故原式为\)
\(分开优化:\)
\(1.\)
\(2.\)
\(3.\)
\(4.\)
\(故原式优化为\)
\(其中T_i,t_i,a_i,b_i,A_i,B_i都可以O(n)预处理\)
\(附代码:\)
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod = 1e9+7;
const int N = 5e5+10;
int n;
ll tmp;
ll a[N],b[N],A[N],B[N],t[N],T[N];
ll ans;
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
cin>>n;
for(int i=1;i<=n;i++){
cin>>tmp;
a[i] = (tmp + a[i-1])%mod;
A[i] = (a[i] + A[i-1])%mod;
}
for(int i=1;i<=n;i++){
cin>>tmp;
b[i] = (tmp + b[i-1])%mod;
B[i] = (b[i] + B[i-1])%mod;
}
for(int i=1;i<=n;i++){
t[i] = (a[i]%mod*b[i]%mod)%mod;
T[i] = (t[i] + T[i-1])%mod;
}
for(int i=1;i<=n;i++){
ans += (T[n]-T[i-1])%mod;
ans %= mod;
ans += (n-i+1)*t[i-1]%mod;
ans %= mod;
ans -= (b[i-1]*(A[n]-A[i-1]))%mod;
ans = (ans + mod ) % mod;
ans -= (a[i-1]*(B[n]-B[i-1]))%mod;
ans = (ans + mod ) % mod;
}
cout<<ans;
return 0;
}
\(AC\)

浙公网安备 33010602011771号