P8590 『JROI-8』这是新历的朝阳,也是旧历的残阳
P8590 『JROI-8』这是新历的朝阳,也是旧历的残阳
本文一开始参考了@ ScottSuperb 的博客的 。
挺好的思维题。
注意,满足数列 。
主题的思路:贪心,数学。
正数阵营:对于分到第 次,平方贡献是 的。
负数阵营:对于分到第 次,平方贡献是 的。
首先,对于分成 的段,我们为了使贡献最大,我们只可以数分成两部分,一部分放在第一段,这一段的数都是负数,因为加 会让他们的平方损失贡献最小。而对于某些负数,即 的情况,这个数在正数阵营中的贡献就更大了,我们把它归入正数阵营之中。
由于本题 ,,数据范围很大,普通的暴力必然是不可行的,考虑数学,即推式子。
前置:我们设 表示第一个正数阵营出现的位置, 表示当前这一分段的总和, 所有正数阵营的和, 表示正数阵营的个数, 为答案。
最开始的时候,所有负数都在负数阵营。
首先考虑正数的贡献。
假设现在划分到第 次,那么当前的正数贡献就是 ,到第 次,正数的贡献就是(多出一个空集)。拆开这两个式子作差,差就是 。
所以,正数的贡献可以由上一次推过来的,时间为 。
对于负数,我们知道,在 的情况下,他可以归入正数中。那么 ,即统计负数归入正数阵营的时候,所给与的贡献,同时 正数阵营个数加一个,第一个正数阵营出现的位置往前推,更新 的答案,即它在负数阵营和正数阵营的差值, 加上当前的数加上 的和。
最后记得取模。
#include<bits/stdc++.h>
using namespace std;
const int N =1e6+10;
const int mod=998244353;
#define int long long
int a[N];
int n,k,b;
int now,ans,sum1,now1;
signed main()
{
// freopen(".in","r",stdin);
// freopen(".out","w",stdout);
cin>>n>>k;
for(int i=0;i<n;i++)
{
cin>>a[i];
b+=a[i]<0;
now=(now+(a[i]+1)*(a[i]+1))%mod;
}
ans+=now;
for(int i=b;i<n;i++)
sum1=(sum1+a[i]+1)%mod;
n-=b;
for(int m=2;m<=k;m++)
{
ans=(ans+(now=(now+sum1*2%mod+n)%mod))%mod;
sum1=(sum1+n)%mod;
while(b>0&&a[b-1]+m>abs(a[b-1]+1))
{
--b,++n;
now1=(a[b]+m)*(a[b]+m)%mod-(a[b]+1)*(a[b]+1)%mod;
ans=(ans+now1)%mod,now=(now+now1)%mod,sum1=(sum1+(a[b]+m))%mod;
}
}
cout<<ans<<endl;
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现