2618 -- 区间(Solution)
题目 : 有一个 \(n\) 个数的序列,一开始所有的数都是 \(0\) ,每次可以将一个区间 $[l,r],(l ≤ r) $内的数 \(+1\) ,求到达最终状态的最少操作次数。
Tag: 模拟、差分
Analysis By LC:
考虑差分的过程,一次操作就等同于 \(s[l]++\, ,s[r+1]--\) 。每个数便是差分数组的前缀和。那么我们可以尝试还原出差分数组:我们将每个数减去前面的那个数,就得到了一个目标序列的差分序列,考虑通过差分数组序列出操作:如果还原后的数组 \(a[i]>0\) ,那么 \(i\) 一定是起点,并且作为 \(a[i]\) 次起点;反之,如果 \(a[i]<0\) ,那么 \(i\) 一定作为 \(-a[i]\) 次终点。接下来就对应输出即可。
Code By LC :
#include<cstdio>
const int N=100005;
int a[N],op[N],ed[N],ans1[N],ans2[N],id,m;
inline int _read()
{
char c; int x=0;
for(;c<'0'||c>'9';c=getchar());
for(;c>='0'&&c<='9';c=getchar())x=(x<<1)+(x<<3)+c-'0';
return x;
}
int main()
{
int n=_read();
for(int i=1;i<=n;i++) a[i]=_read();
for(int i=0;i<=n+1;i++)
{
if(a[i]>a[i-1]) op[i]+=a[i]-a[i-1];
if(a[i]>a[i+1]) ed[i]+=a[i]-a[i+1];
}
int i=1,j=1;
while(true)
{
while(i<=n&&!op[i]) ++i;
while(j<=n&&!ed[j]) ++j;
if(j>n) break;
m++; ans1[m]=i,ans2[m]=j;
--op[i]; --ed[j];
}
printf("%d\n",m);
for(int i=1;i<=m;i++) printf("%d %d\n",ans1[i],ans2[i]);
}