[NOIP模拟]新排序
2017-10-17 21:57
197 查看
样例输入:
4
5
1 2 3 4 5
5
5 4 3 2 1
5
1 2 3 2 1
5
2 4 1 3 5
样例输出:
5
1 2 3 4 5
0
2
1 2
3
2 3 5
数据范围:
对于40%的数据,N≤1000;
对于70%的数据,N≤50000;
对于100%的数据,T≤5;N≤100000;
题目分析:
考试总结:考试的时候,想用队列加各种情况打标记来处理,还激动的以为是正解。但是对拍又各种过不了,苦苦思考修改,结果快考完的时候,幡然醒悟单纯的队列是无法实现的。
分析:我们可以先扫一遍将不合法的点的左右两边(各一个)的数加入一个队列(可加入的条件,预备加入的数没有被加入且不是不合法的点,实际上加入的是一段不合法序列的左右两边的数),因为当你删掉这一段后,影响的就是这两个数。于是队列里又有了一些数,再对这些数判断是否有不合法的序列,重复上面的操作(此时加入左右两边的数是指不合法的数在原序列的左右两边),直到队列里面没有不合法的数。也许你会问,这和暴力模拟有什么区别。暴力模拟,每次要检查的是除掉当前不合法数后的整个序列。而上面的方法只加入不合法序列两端的两个数,因为每个数只会入队列一次(因为要判断是否已加入且它是不是不合法的数(不合法是只要这个数不合法过,就会一直标记))所以O(n)。
附代码:
4
5
1 2 3 4 5
5
5 4 3 2 1
5
1 2 3 2 1
5
2 4 1 3 5
样例输出:
5
1 2 3 4 5
0
2
1 2
3
2 3 5
数据范围:
对于40%的数据,N≤1000;
对于70%的数据,N≤50000;
对于100%的数据,T≤5;N≤100000;
题目分析:
考试总结:考试的时候,想用队列加各种情况打标记来处理,还激动的以为是正解。但是对拍又各种过不了,苦苦思考修改,结果快考完的时候,幡然醒悟单纯的队列是无法实现的。
分析:我们可以先扫一遍将不合法的点的左右两边(各一个)的数加入一个队列(可加入的条件,预备加入的数没有被加入且不是不合法的点,实际上加入的是一段不合法序列的左右两边的数),因为当你删掉这一段后,影响的就是这两个数。于是队列里又有了一些数,再对这些数判断是否有不合法的序列,重复上面的操作(此时加入左右两边的数是指不合法的数在原序列的左右两边),直到队列里面没有不合法的数。也许你会问,这和暴力模拟有什么区别。暴力模拟,每次要检查的是除掉当前不合法数后的整个序列。而上面的方法只加入不合法序列两端的两个数,因为每个数只会入队列一次(因为要判断是否已加入且它是不是不合法的数(不合法是只要这个数不合法过,就会一直标记))所以O(n)。
附代码:
#include<iostream> #include<cstdlib> #include<cstdio> #include<ctime> #include<cmath> #include<cstring> #include<string> #include<cctype> #include<iomanip> #include<algorithm> using namespace std; const int N=1e5+10; const int INF=0x3f3f3f3f; int t,a ,n,cnt,tot,po,ans; bool exist ,del ,flag; struct node{ int pos;//位于原序列的位置 int val;//大小 }q ; int readint() { char ch;int i=0,f=1; for(ch=getchar();(ch<'0'||ch>'9')&&ch!='-';ch=getchar()); if(ch=='-') {ch=getchar();f=-1;} for(;ch>='0'&&ch<='9';ch=getchar()) i=(i<<3)+(i<<1)+ch-'0'; return i*f; } int main() { //freopen("sort.in","r",stdin); //freopen("sort.out","w",stdout); t=readint(); while(t--) { memset(del,false,sizeof(del)); memset(exist,false,sizeof(exist)); flag=false;cnt=0; n=readint(); for(int i=1;i<=n;i++) a[i]=readint(); a[0]=-INF;a[n+1]=INF;//方便后面的判断 for(int i=1;i<=n;i++) if(a[i]>a[i+1]||a[i]<a[i-1])//判断是否合法 { del[i]=true;//此数不合法标记 flag=true;//是否有不合法数标记 } for(int i=1;i<=n;i++) { if(del[i]==true) { if(i>1&&del[i-1]==false&&exist[i-1]==false)//看左边能否加入队列 {q[++cnt].pos=i-1;q[cnt].val=a[i-1];exist[i-1]=true;} if(i<n&&del[i+1]==false&&exist[i+1]==false)//看右边能否加入队列 {q[++cnt].pos=i+1;q[cnt].val=a[i+1];exist[i+1]=true;} } } while(flag==true)//循环执行 { q[0].val=-INF;q[cnt+1].val=INF; flag=false;tot=0; for(int i=1;i<=cnt;i++)//判队列断是否有不和法的数 { if(q[i].val>q[i+1].val||q[i].val<q[i-1].val) {del[q[i].pos]=true;flag=true;exist[q[i].pos]=false;} } for(int i=1;i<=cnt;i++) { po=q[i].pos; if(del[po])//与上面同理 { if(po>1&&del[po-1]==false&&exist[po-1]==fal a625 se) {q[++tot].pos=po-1;q[tot].val=a[po-1];exist[po-1]=true;} if(po<n&&del[po+1]==false&&exist[po+1]==false) {q[++tot].pos=po+1;q[tot].val=a[po+1];exist[po+1]=true;} } else q[++tot]=q[i];//合法的依旧加入队列 } cnt=tot; } ans=0; for(int i=1;i<=n;i++) if(del[i]==false) ans++; printf("%d\n",ans); for(int i=1;i<=n;i++) if(del[i]==false) cout<<a[i]<<" ";//printf("%d ",a[i]); printf("\n"); } return 0; }
相关文章推荐
- 【JZOJ5232】【NOIP2017模拟A组模拟8.5】带权排序
- noip2000税收与补贴问题 (模拟,排序)
- JZOJ 5232【NOIP2017模拟】带权排序(概率,线段树)
- 【jzoj5232】【NOIP2017模拟A组模拟8.5】【带权排序】【线段树】
- 【NOIP模拟】排序
- 【NOIP2016提高A组模拟9.14】排序
- [NOIP2017模拟]新排序
- JZOJ__Day 3:【NOIP普及模拟】排序(sort)
- NOIP2008 双栈排序 染色+模拟
- 【NOIP2011模拟9.17】数字生成游戏
- Noip 1998 洛谷P1011 车站 - 模拟
- 【NOIP2016提高A组模拟9.3】总结
- 【NOIP2014模拟8.21】签到题3 jzoj 3797 树链剖分
- JZOJ.4710【NOIP2016提高A组模拟8.17】Value
- 【2014.8.17NOIP普及组模拟】数池塘//2018.2.3
- [NOIP模拟] sort
- 3450. 【NOIP2013模拟联考3】山峰(summits) (Standard IO)
- Value【NOIP2016提高A组模拟8.17】
- JZOJ5373. 【NOIP2017提高A组模拟9.17】信仰是为了虚无之人 并查集+启发式合并