训练赛---咏叹
来源:互联网 发布:android 数据库路径 编辑:程序博客网 时间:2024/06/06 01:55
咏叹
题目来源
安师大附中训练题目
题目大意
给定一个1到n的排列A,对其进行冒泡排序:
counter=0While A不是升序的 counter=counter+1 For i=1 to n-1 If A[i]>A[i+1] Then Swap(A[i],A[i+1]) End If End ForEnd While
那么经过几轮排序之后A序列会变成升序呢?(即counter变量的值)
输入格式
输入n,S,B,C,D五个整数,数据按以下方式生成:
For i=1 to n A[i]=i S=(S*B+C) mod D Swap(A[i],A[(S mod i)+1])End For
输出格式
一行,一个整数,表示冒泡排序进行的轮数,即counter变量的值.
数据范围
对于30%的数据,
对于50%的数据,
对于70%的数据,
对于100%的数据,
限制
时间限制:2s
空间限制:233M (原题如此)
题解
按照冒泡排序进行模拟,
我拿到题的第一反应是打表找规律,然而好像没有发现什么明显的规律。之后我就开始尝试寻找各种结论,然而都有反例。这个时候我意识到,解决这种问题必须要寻找出每次操作都遵循的不变量,或者是通行的规则。
首先我想到了逆序对,然而每一轮消去的逆序对数量是变化的,我们没有办法通过逆序对来求得最终的轮数。
然后我开始注意波浪形,关注波峰波谷以及上升链下降链,没有找到出路。
我开始关注到冒泡排序的逆操作,考虑在一个升序序列中交换一些数,会给答案带来怎样的贡献。也没有发现有用的性质。
几经磨难,我还是发现了正解。我们注意到,对于一个数而言,如果它的左侧存在比它大的数,那么这些比它大的数肯定会越过它,到达右侧的区域。而且每一轮操作左侧有且仅有一个比它大的数越过它。我们不妨将第i个数的左侧比A[i]大的数的个数记作f[i],那么最终的轮数一定满足
至此我们可以用树状数组维护左侧比A[i]小的数的个数,可得70分.
怎么优化呢?
对于A[i]=1而言,f[i]=i-A[i];
对于A[i]=2而言,如果1在2左侧,那么f[i]=i-A[i]成立;如果1在2右侧,那么f[i]一定不是最大值,因为1处的f值肯定大于f[i];以此类推,对于A[i]=k而言,如果1~k-1都在k左侧,则f[i]=i-A[i];否则,f[i]必定不是最大值。于是
至此我们得到了O(n)算法。要想拿满100分,必须要常数足够小;实际评测中,用long long的,取模较多的都只有70分.
Code
#include<cstdio>#include<algorithm>using namespace std; #define MAXN 30000500int S,B,C,D,A[MAXN],n; int main(){ scanf("%d%d%d%d%d",&n,&S,&B,&C,&D); for(int i=1;i<=n;i++) { A[i]=i; S=(1ll*S*B+C)%D; swap(A[i],A[S%i+1]); } int ans=0; for(int i=1;i<=n;i++) { ans=max(ans,i-A[i]); } printf("%d\n",ans); return 0;}
代码非常短!
- 训练赛---咏叹
- 12月9日 华丽咏叹者
- 训练赛
- 训练集--训练赛8
- 训练集---训练赛9
- 训练集---训练赛10
- 训练集---训练赛11
- 训练集---训练赛12
- 训练集---训练赛13
- 训练集---训练赛14
- 寒假训练---训练赛2--Fighting
- 寒假训练--训练赛2--Good Luck!
- 寒假训练--训练赛2--加密术
- 省赛训练赛
- 20120810训练赛总结
- 20120811训练赛总结
- 13训练赛01
- 训练赛(一)
- windows phone listbox的点击事件
- [bzoj1293][SCOI2009]生日礼物 单调队列优化dp
- 选择排序
- ZOJ--1003:Crashing_Balloon(因子分解)
- linux下的父子进程的验证代码
- 训练赛---咏叹
- Maven快速入门
- 旧版漏洞 Bug 被发现可致 Win7/8.1 “崩溃”
- MySQL入门--删除数据库、修改数据库编码集、显示数据库创建信息
- URL与资源(http权威指南第二章)
- 【转】Windows Phone在隔离存储里存取图片文件
- 18. Python开发--函数杂货铺(内置函数,递归)
- 二叉树
- mysql组合索引"最左前缀"的结果。简单的理解就是只从最左面的开始组合