您的位置:首页 > 其它

cf #344 div2 -C. Report

2016-03-09 16:30 232 查看
为什么我感觉这道题其实真的有点难,但还是有很多人过, 还是我太弱了!!!

题意:给一个长度为n (n<200000) 的数列。 然后m次操作,每一次操作输入 t,r。 对前r个操作,做递减或者递增的排序!

2016-5-10回顾:

如果先对 前n个操作,再对前n+1 (或者>n)个操作,肯定第一次操作是可以跳过的,

所以我们可以筛选出一个操作长度的递减序列 操作即可。 但这样有可能T的,很容易被数据卡掉。

再想可以发现,其实每一次排序都确定了一些值,还是筛选出 m’ 个有效操作,记录每一个操作从尾部的i

开始,记录这次操作是从小到大还是从大到小, 然后开一个全局表示最小值minn(从1开始),最大值maxn(从n 开始),然后从i - —-j (下一次操作开始的地方), 依次填入minn或则maxn 并逐个递增,减(根据这一次操作排列方式来),,, 理论ac 应该是没问题的。 简单题,不难

注意: 我觉得这个地方题目并没有表达清楚,我一开始以为只要是非减就行了,但其实貌似题目的输出,非减就代表了递增!!!

然后呢m次操作之后,会得到一个新的序列,输出这个序列就好了。

一开始的想法: 如果有操作i,j,存在i < j,并且ri < rj ,那么不管他是不是递增还是递减排列,操作i都是一次无效的操作。

然后就开始写排序了,这样很容易被某一组数据卡死超时,这种想法还是太水了~,

仔细想想上面的分析之后不难发现一个最最关键的地方:

有效操作呈这样的分布:

…的长度代表某次操作的r[i]的大小。

……………………………………………………….

…………………………………………………..

……………………………………………..

…………………………………………

……………………………… ……

………………………………..

………………………

………………..

也就是:有效操作的序号 i,j 满足i < j,则 r[i] > r[j];

再想一下一个小方法这道题其实就是一道水题了:

我们可以得到所有操作的最大值maxn ,也就是所有操作的是围绕着前maxn 个数来排序。

那么我们可以先把这前maxn个数从小到大排好序;

如果第一个有效操作 是递增:

………………………………………………………………. 第一个有效操作

…………………………………………….. [b]***********[/b] 第二个有效操作

—————————————|—————-| 中间这一段 是不是就是最大的几个值??

若第一个有效操作是递减,拿着一段就是最小的几个值!

讲到这里应该就很明显了:

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<math.h>
#include<algorithm>
#include<stdlib.h>
#include<queue>
#include<stack>
#include<map>
#include<vector>
#define mem(a) memset(a,0,sizeof(a))
#define pfn printf("\n")
#define sf  scanf
#define pf  printf
#define fr(i,n) for(int i=0;i<n;i++)
#define INF 0x7fffffff   //INT_MAX
#define inf 0x3f3f3f3f   //
const double PI = acos(-1.0);
const double e = exp(1.0);
template<class T> T gcd(T a, T b) { return b ? gcd(b, a % b) : a; }
template<class T> T lcm(T a, T b) { return a / gcd(a, b) * b; }
using namespace std;
#define lson l , mid , rt << 1
#define rson mid + 1 , r , rt << 1 | 1
using namespace std;
#define rep(i,s,t) for(int i=int(s); i<int(t); i++)
#define mst(A,k) memset(A,k,sizeof(A))
int Scan()
{
int res = 0, ch, flag = 0;

if((ch = getchar()) == '-')             //判断正负
flag = 1;
else if(ch >= '0' && ch <= '9')         //得到完整的数
res = ch - '0';
while((ch = getchar()) >= '0' && ch <= '9' )
res = res * 10 + ch - '0';
return flag ? -res : res;
}

int a[200005];
int t[200005],r[200005];
int flag[200005];
int maxn;
int num[200005];
int ans[200005];
bool cmp(int a,int b){
return a<b;
}

int main(){
int n,m;
//freopen("1.txt","r",stdin);
while(~scanf("%d %d",&n,&m)){
mem(flag);
maxn=0;
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
for(int i=1;i<=m;i++){
scanf("%d %d",&t[i],&r[i]);
flag[r[i]]=t[i]; //用flag保存该数组是递增还是递减
num[r[i]]=i;    //保存每一步操作处理前maxn个。
maxn=max(maxn,r[i]);
}
sort(a+1,a+maxn+1,cmp);
int ll=1,rr=maxn;
int xuhao=0;
int now_flag;   //保存flag值
for(int i=maxn;i>0;i--){
if(flag[i] && num[i]>xuhao){   // 如果存在 对于前i个数的 操作
xuhao=num[i];  //num必须在上一次的序列后面,才会进行操作
now_flag=flag[i];
}
// 如果不存在,那么之前的那一次操作依然会对往后的几个数值有影响
if(now_flag==2){
ans[i]=a[ll];
ll++;
}
else{
ans[i]=a[rr];
rr--;
}
}
for(int i=1;i<=maxn;i++)
i==1?printf("%d",ans[i]):printf(" %d",ans[i]);
for(int i=maxn+1;i<=n;i++)
printf(" %d",a[i]);
printf("\n");
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: