问题 N: 扶桑号战列舰
时间限制: 1 Sec 内存限制: 128 MB Special Judge
题目描述
众所周知,一战过后,在世界列强建造超无畏级战列舰的竞争之中,旧日本海军根据“个舰优越主义”,建造了扶桑级战列舰,完工时为当时世界上武装最为强大的舰只。
同时,扶桑号战列舰也是舰岛最为科幻的战列舰。
当然,要建造这样的舰船,科技水平是必须的。
同样众所周知的是,德意志科学技术天下第一,所以IJN的司令官从德国学来了一种先进的建船方法。
一只战舰横过来可以看做一个长度为n的序列,每个位置有一个数ai表示这个位置设计的高度。这种先进的造船技术可以每次将一个区间[l,r]内的所有位置高度都+1,求到达最终设计状态的最少操作次数。
如果你不能及时完成的话,IJN司令官会奖励你去参加苏里高海战。
输入
第一行包含一个整数n,表示序列的长度。
第二行包含n个非负整数a1,a2,a3,…,an,表示最终的状态。
输出
输出的第一行是一个正整数m,表示最少的操作次数。
接下来m行每行两个正整数li,ri,表示一次操作。
你需要保证1≤li≤ri≤n。
保证最少次数m≤105,输出可以以任意顺序输出。
样例输入
复制样例数据
6
2 3 3 3 3 3
样例输出
3
1 6
1 6
2 6
提示
这个题可以用单调栈来做,注意这里栈中是保存数的编号!从左到右依次让数列中的数与栈顶元素对应的在数列中的数值进行比较,只要前者大,就让其编号入栈(也就是按值的大小递增入栈);如果前者小于后者,这时就要保存一个区间的左右界(左界为栈顶元素的值,右界为当前数列中进行比较的数的编号-1),然后让后者-1,一直到栈顶元素对应的值等于栈中第二个元素对应的值时,让栈顶元素出栈,这样就能继续保存这个区间内下一个应该保存的子区间了;当两者相等时,则不用进行任何操作(前者不用入栈,栈中元素也不用变),然后继续访问下一个数列中的数。。。。。。
完整代码:
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int maxn=1e5+5;
stack<int>t;
typedef struct internal
{
int l,r;
}in;
in seq[maxn];
int a[maxn],n,m;
signed main()
{
// ios::sync_with_stdio(false);
// cin.tie(0);
scanf("%lld",&n);
for(int i=1;i<=n;i++)
{
cin>>a[i];
}
t.push(0);
for(int i=1;i<=n+1;i++)
{
if(a[i]>a[t.top()])
{
t.push(i);
}
while(a[i]<a[t.top()])
{
seq[++m].l=t.top();
seq[m].r=i-1;
a[t.top()]--;
int x=t.top();//保存栈顶元素
t.pop();//先让栈顶元素出栈,后面再判断是否真的让其出栈
if(a[x]>a[t.top()])//栈顶元素对应的值和栈中第二个元素对应的值比较
{
t.push(x);//如果栈顶元素大就再让其如栈(相当于没对栈顶元素进行出栈操作),这样就实现了一直到栈顶元素对应的值等于栈中第二个元素对应的值时,让栈顶元素真正出栈
}
}
}
printf("%lld\n",m);
for(int i=1;i<=m;i++)
{
printf("%lld %lld\n",seq[i].l,seq[i].r);
}
return 0;
}