差分【bzoj3043】IncDec Sequence
Description
给定一个长度为n的数列{a1,a2...an},每次可以选择一个区间[l,r],使这个区间内的数都加一或者都减一。 问至少需要多少次操作才能使数列中的所有数都一样,并求出在保证最少次数的前提下,最终得到的数列有多少种。
Input
第一行一个正整数n 。
接下来n行,每行一个整数,第i+1行的整数表示ai。
Output
第一行输出最少操作次数。
第二行输出最终能得到多少种结果。
表示看到题很懵逼啊 emm
解释感觉不是很对,希望大佬能指出错误 qwq
这个是差分应该不难看出。
我们首先处理出差分数组。
想要我们的数列中的数相同,那么我们必须要保证差分数组中\(2-n\)全部都是\(0\)。
那么现在我们的问题就变成了,如何使用最小的步数使得差分数组中\(2-n\)部分全部为\(0\)。
我们用\(s1\)记录差分数组中所有正数的和.\(s2\)记录差分数组中所有负数的和。
此时,正负可消。
什么是正负可消?
我们将区间内的数加\(1\)与将区间内的数减\(1\)等效。
所以对\(s1,s2\)取\(max\)即为第一问答案。
此时会有剩余部分,我们可以考虑对其单点修改,或者连同\(1\)到这个点修改。
那么我们的答案就是两部分的中间的数的数量(包括两端)
即为\(|s1-s2|+1\)
代码
#include<cstdio>
#include<iostream>
#include<algorithm>
#define R register
#define lo long long
using namespace std;
inline void in(R int &x)
{
R int f=1;x=0;char s=getchar();
while(!isdigit(s)){if(s=='-')f=-1;s=getchar();}
while(isdigit(s)){x=x*10+s-'0';s=getchar();}
x*=f;
}
int n,last,x;
lo s1,s2;
int main()
{
in(n);in(last);
for(R int i=2;i<=n;i++)
{
in(x);
if(x-last>0)s1+=x-last;
else s2+=(last-x);
last=x;
}
printf("%lld\n%lld",max(s1,s2),abs(s1-s2)+1);
}
除特殊声明外,本博客作品均由顾z创作。
未经博主允许,不得转载