Luogu P4552 [Poetize6] IncDec Sequence 更好的题解

原题链接

第一步对于学过差分的人应该不难想
定义差分数组 diss.t.dis[i]=a[i]a[i1]
那么不难发现问题一只要让 dis[2]...dis[n]中全部为 0 即可
区间[l,r]加一操作在差分数组中意味着dis[l]=dis[l]+1,dis[r+1]=dis[r+1]1
即在差分数组中每次选取(x,y),dis[x]=dis[x]+1,dis[y]=dis[y]1
注意这里x,y可以选取1...n+1
减一同理
最后要使dis[2]...dis[n]全为0,首先在dis[2]...dis[n]选取一个正数和一个负数是他们配对加一或减一,直到最后只剩下一个数,不难发现这个数就是dis[2]...dis[n]中正数的和sum+和负数的和的绝对值|sum|的差,让他与dis[1]或dis[n+1]配对即可

最后整理可得:min(sum+,sum)+|sum+|sum||,即max(sum+,|sum|)就是第一小问答案

对于第二小问,不难注意答案序列的不同只和在第一小问中最后剩下的那个数k=sum+|sum|+1有关
我们这里不妨设k>0,那么它可以和1或n+1配对,这里两个操作就代表了原数组a[1,k1]全部加一和原数组a[k,n]全部减一,也就产生了两种不同的序列
那么这两种操作进行的次数的和必然是k,那么就产生了k+1中不同的选法(第一个操作进行0...k次)
对于k<0的情况可以同样地进行讨论
那么第二问答案就是k+1=|sum+|sum||+1

//c++AC代码
#include <bits/stdc++.h>
using namespace std;

int n,a[(int)1e5+5],dis[(int)1e5+5];
long long sum_z,sum_f,rest;

int main()
{
	scanf("%d",&n);
	for(int i = 1;i <= n;++i)
	{
		scanf("%d",a+i);
	}
	for(int i = 1;i <= n;++i)
	{
		dis[i]=a[i]-a[i-1];
	}
	for(int i = 2;i <= n;++i)
	{
		if(dis[i] > 0)
			sum_z+=dis[i];
		else 
			sum_f+=dis[i];
	}
	rest=sum_z+sum_f;
	printf("%lld\n",max(sum_z,std::abs(sum_f)));
	printf("%lld",(long long)std::abs(sum_z-std::abs(sum_f))+1);
	return 0;
}
posted @   xxxxxxxb  阅读(104)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效
点击右上角即可分享
微信分享提示