原题链接:https://www.luogu.com.cn/problem/P4552
题意解读:对一组数字序列,进行若干次区间+1或者-1操作,最终使得所有数字一样,计算最少的操作次数,以及能得到多少种不同序列。
解题思路:
要使得序列每一个数字都相同,则其差分除了第一项之外其余项都是0。
因此,问题转化为:给定一个差分数组a[],每次对两个数a[l],a[r+1]分别进行+1、-1操作(对于前缀和数组就是对[l,r]每个数都+1或-1),最终使得除a[1]之外都变成0,而a[1]的数值决定其前缀和数组有多少种不同的序列。
一共有如下几种可能的操作:
a[]中除a[1]外存在一正一负时:
操作一:对正数-1,对负数+1,这样可以尽快将所有数变为0,保证操作次数最少
a[]中除a[1]外只有正数或者负数时:
操作二:可以对a[1]+1或-1,对正数-1或对负数+1,该操作影响最终序列的种类
操作三:可以对正数-1或对负数+1,对a[n+1]+1或-1
所以,对于一个差分数组a[],设除了a[1]所有正数之和为up,所有负数之和的绝对值为down
那么优先进行操作一,直到只剩下正数或者负数,操作次数为min(up, down)
接下来,只剩下正数或者负数,可以进行操作二或者操作三,任选其一即可,操作次数为abs(up - down)
总操作次数为:min(up, down) + abs(up - down)
可能得到的序列取决于进行操作二的次数,可以有0 ~ abs(up - down)次操作二,一共对应1 + abs(up - down)种序列。
100分代码:
#include <bits/stdc++.h>
using namespace std;
const int N = 100005;
int s[N], a[N];
int n;
long long up, down;
int main()
{
cin >> n;
for(int i = 1; i <= n; i++)
{
cin >> s[i];
a[i] = s[i] - s[i - 1];
}
for(int i = 2; i <= n; i++)
{
if(a[i] > 0) up += a[i];
else if(a[i] < 0) down += abs(a[i]);
}
cout << min(up, down) + abs(up - down) << endl;
cout << 1 + abs(up - down);
return 0;
}
标签:Sequence,int,洛谷题,P4552,up,down,负数,操作,正数 From: https://www.cnblogs.com/jcwy/p/18336665