P5686 [CSP-S2019 江西] 和积和 题解

PART 1: 题目大意

s(l,r)=i=lrai×bi,求 l=1nr=1ns(l,r)

PART 2:解题思路

从数据范围可以看出来,这是一道思维题,我没需要把体面给出的柿子通过转化使其复杂度下降。从数据范围看出,这里需要时间复杂度大约 O(n)

不妨先把题目给的柿子拆开来看是否存在规律:

ans=a1×(i=1nbi+i=1n1bi+i=1n2bii=11bi)+a2×(i=1nbi+i=1n1bi+i=1n2bii=12bi+i=2nbi+i=2n1bi+i=2n2bii=22bi)

am 对应的括号中的柿子为 f(m),则:

f(m)=i=1nbi+i=1n1bi+i=1n2bii=1mbi+i=2nbi+i=2n1bi+i=2n2bii=2mbi+i=mnbi+i=mn1bi+i=mn2bii=mmbi

这样看上去貌似没有什么规律,我们举两个例子来看

f(1)=i=1nbi+i=1n1bi+i=1n2bii=11bi=i=1nbi×(ni+1)

f(2)=i=1nbi+i=1n1bi+i=1n2bii=12bi+i=2nbi+i=2n1bi+i=2n2bii=22bi=i=1nbi×(ni+1)b1+i=2nbi×(ni+1)

感觉他们都有很相似的 i=knbi×(ni+1) 这部分,不妨设 sum=i=1nbi×(ni+1),再用 sum 将其替换,那么会得到:

f(1)=sum

f(2)=2sum(n+1)b1

f(3)=3sum2(n+1)b1(n1)b2

以此类推,那么得到:

f(m)=m×sumi=1m1(n+1)b1×(mi)

这样的柿子是 O(n2) 的,于是我们就拿到了 70pts 的分数,代码如下:

#include<bits/stdc++.h> #define MAXN 500010 #define MOD 1000000007ll using namespace std; typedef long long ll; int n; ll a[MAXN],b[MAXN],sum,ans; int main(){ // freopen("sum.in","r",stdin); // freopen("sum.out","w",stdout); scanf("%d",&n); for(int i = 1;i <= n;i++) scanf("%lld",&a[i]), a[i] %= MOD; for(int i = 1;i <= n;i++) scanf("%lld",&b[i]), b[i] %= MOD; for(int i = 1;i <= n;i++) sum += (n-i+1) * b[i], sum %= MOD; for(int i = 1;i <= n;i++){ ll tmp = ( sum * i ) % MOD; for(int j = 1;j < i;j++) tmp = ( tmp - ( ( ( ( b[j] * (n+1) ) % MOD ) * (i-j) ) % MOD ) + MOD ) % MOD; ans = ( ans + tmp * a[i] ) % MOD; } printf("%lld\n",ans); return 0; }

那么如何才能拿到满分呢?考虑把刚刚推出来的柿子进一步优化。观察发现,将柿子中的求和项裂开来,得到:

f(m)=m×sum(n+1)(mi=1m1bii=1m1bi×i)

可以预处理出 bi 以及 bi×i 的前缀和,将柿子优化到 O(n),于是得到了 Accepted 的代码:

#include<bits/stdc++.h> #define MAXN 500010 #define MOD 1000000007ll using namespace std; typedef long long ll; ll n; ll sum,ans; ll a[MAXN],b[MAXN],sum_b[MAXN],sum_mult_b[MAXN]; int main(){ // freopen("sum.in","r",stdin); // freopen("sum.out","w",stdout); scanf("%lld",&n); for(ll i = 1;i <= n;i++) scanf("%lld",&a[i]), a[i] %= MOD; for(ll i = 1;i <= n;i++) scanf("%lld",&b[i]), b[i] %= MOD; for(ll i = 1;i <= n;i++){ sum_b[i] = (sum_b[i-1] + b[i]) % MOD; sum_mult_b[i] = (sum_mult_b[i-1] + (b[i] * i) % MOD) % MOD; } for(ll i = 1;i <= n;i++) sum += (n-i+1) * b[i], sum %= MOD; for(ll i = 1;i <= n;i++){ ll tmp = ( (sum * i) % MOD - ( (n+1) * ((( i * sum_b[i-1] ) % MOD - sum_mult_b[i-1] + MOD) % MOD + MOD) % MOD ) % MOD + MOD ) % MOD; ans = ( ans + ( tmp * a[i] ) % MOD ) % MOD; } printf("%lld\n",ans); return 0; }

__EOF__

本文作者NightTide
本文链接https://www.cnblogs.com/NightTide/p/16213502.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   Night_Tide  阅读(159)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 25岁的心里话
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示