【CF 549G Happy Line】排序

题目链接:http://codeforces.com/problemset/problem/549/G

题意:给定一个n个元素的整数序列a[], 任意时刻对于任一对相邻元素a[i-1]、 a[i],若a[i-1] < a[i] 则要依次执行如下两个操作:

  1. a[i-1]--, a[i]++;

  2. 交换a[i-1]和a[i]的位置。

经过若干次1、2操作后,若能使整个序列变成非降的,则输出最终的序列;否则输出":("。

数据范围:n 属于 [1, 2*10^5], a[i] 属于[0, 10^9]

思路:首先想到交换排序,但n 在10^5所以n^2的排序不可取。后来模拟快排的过程推出了样例,如下:

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <algorithm>
 4 #include <queue>
 5 #define CLEAR(A, X) memset(A, X, sizeof(A))
 6 #define REP(N) for(int i=0; i<(N); i++)
 7 #define REPE(N) for(int i=1; i<=(N); i++)
 8 #define FREAD(FN) freopen((FN), "r", stdin)
 9 #define pb(a) push_back(a)
10 #define pf() pop_front()
11 using namespace std;
12
13 const int MAX_N = 200005;
14 int n;
15 int a[MAX_N];
16 int flag;
17 void partition(int s, int e){
18     if(s == e) return ;
19     int i = s, j = e - 1;
20     //printf("i %d j %d*******\n", i, j);
21     while(i < j){
22         while(i < j && a[j] >= a[i]) j--;
23         if(i < j){
24             a[j] += j - i;
25             if(a[i] == a[j]){
26                 flag = 1;
27                 return ;
28             }
29             a[i] -= j - i;
30             swap(a[i], a[j]);
31             i++;
32         }
33
34         while(i < j && a[i] <= a[j]) i++;
35         if(i < j){
36             a[i] -= j - i;
37             if(a[i] == a[j]){
38                 flag = 1;
39                 return ;
40             }
41             a[j] += j - i;
42             swap(a[i], a[j]);
43             j--;
44         }
45         // for(int k=0; k<n; k++) printf("%d ", a[k]);
46         // printf("\n");
47     }//i == j
48     partition(s, i);
49     partition(i+1, e);
50 }
51
52 int main()
53 {
54     scanf("%d", &n);
55     REP(n) scanf("%d", &a[i]);
56     flag = 0;
57     partition(0, n);
58     if(flag) printf(":(\n");
59     else{
60         REP(n) printf("%d ", a[i]);
61         printf("\n");
62     }
63     return 0;
64 }

quickSort,i, j相对往中间走

但对于第六个test(

5
15 5 8 6 3

)得到的结果是错的,尝试改用i, j 指针同方向走来构造轴点,如下,但还是构造不出正确的结果。

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <algorithm>
 4 #include <queue>
 5 #define CLEAR(A, X) memset(A, X, sizeof(A))
 6 #define REP(N) for(int i=0; i<(N); i++)
 7 #define REPE(N) for(int i=1; i<=(N); i++)
 8 #define FREAD(FN) freopen((FN), "r", stdin)
 9 #define pb(a) push_back(a)
10 #define pf() pop_front()
11 using namespace std;
12
13 const int MAX_N = 200005;
14 int n;
15 int a[MAX_N];
16 int flag;
17 void partition(int s, int e){
18     if(s == e) return ;
19     int i = s, j = s + 1;
20     int cur = s;
21     //printf("i %d j %d*******\n", i, j);
22     while(i < e && j < e){
23         while(i < j && j < e && a[j] >= a[i]) j++;
24         if(i < j && j < e){
25             a[j] += j - i;
26             if(a[i] == a[j]){
27                 flag = 1;
28                 return ;
29             }
30             a[i] -= j - i;
31             swap(a[i], a[j]);
32             cur = j;
33             i = j + 1;
34         }
35
36         while(j < i && i < e && a[i] >= a[j]) i++;
37         if(j < i && i < e){
38             a[j] -= i - j;
39             if(a[i] == a[j]){
40                 flag = 1;
41                 return ;
42             }
43             a[i] += i - j;
44             swap(a[i], a[j]);
45             cur = j;
46             j = i + 1;
47         }
48         // for(int k=0; k<n; k++) printf("%d ", a[k]);
49         // printf("\n");
50     }//i == j
51     partition(s, cur);
52     partition(cur+1, e);
53 }
54
55 int main()
56 {
57     scanf("%d", &n);
58     REP(n) scanf("%d", &a[i]);
59     flag = 0;
60     partition(0, n);
61     if(flag) printf(":(\n");
62     else{
63         REP(n) printf("%d ", a[i]);
64         printf("\n");
65     }
66     return 0;
67 }

quickSort,i, j从左往右走

于是看题解了,以下是题解的思路,思想仍是排序,(虽然tag上写了greedy,但我没想明白哪里用到了贪心策略):

由于swap(a[i-1], a[i])时,向左的a[i]在数值上"收益"了1,向右的a[i-1]在数值上"消耗"了1,现在把由交换产生的“收益/消耗”变化量从a[i]的原始数值中分离开来。

如左图,每一列对应一个位置 i ,其中黑色的“台阶”加上黄色的“塔”为原始的a[i]值,现在规定从左到右台阶的高度从n 均匀递减到 1, 记黄色的塔高 b[i] = 原始高度a[i] - 台阶高度(n - i)(i从0起始);这样每个a[i] 向左交换相当于上一个台阶,向右交换为下一个台阶,对应的塔高b[i]是不变的,如右图。所以我们只需计算出序列b[i]并把它排成非降序,然后再加上对应位置的台阶高度就是最终结果了。对于":("的情况,只需得到结果后扫描一遍检查是否确实非降序即可。

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <algorithm>
 4 #include <queue>
 5 #define CLEAR(A, X) memset(A, X, sizeof(A))
 6 #define REP(N) for(int i=0; i<(N); i++)
 7 #define REPE(N) for(int i=1; i<=(N); i++)
 8 #define FREAD(FN) freopen((FN), "r", stdin)
 9 #define pb(a) push_back(a)
10 #define pf() pop_front()
11 using namespace std;
12
13 const int MAX_N = 200005;
14 int n;
15 int a[MAX_N];
16 int flag;
17
18 int main()
19 {
20     scanf("%d", &n);
21     REP(n) scanf("%d", &a[i]);
22     flag = 0;
23     REP(n) a[i] -= n - i;
24     sort(a, a+n);
25     a[0] += n;
26     for(int i=1; i<n; i++){
27         a[i] += n - i;
28         if(a[i] < a[i-1]){
29             flag = 1;
30             break;
31         }
32     }
33
34     if(flag) printf(":(\n");
35     else{
36         REP(n) printf("%d ", a[i]);
37         printf("\n");
38     }
39     return 0;
40 }
时间: 2024-10-14 10:01:43

【CF 549G Happy Line】排序的相关文章

CodeForces 549G Happy Line

Happy Line Time Limit:1000MS     Memory Limit:262144KB     64bit IO Format:%I64d & %I64u Submit Status Practice CodeForces 549G Description Do you like summer? Residents of Berland do. They especially love eating ice cream in the hot summer. So this

Codeforces 549G Happy Line[问题转换 sort]

G. Happy Line time limit per test 1 second memory limit per test 256 megabytes input standard input output standard output Do you like summer? Residents of Berland do. They especially love eating ice cream in the hot summer. So this summer day a larg

Codeforces 549G. Happy Line 贪心

很有意思的贪心: Let's reformulate the condition in terms of a certain height the towers, which will be on the stairs. Then an appropriate amount of money of a person in the queue is equal to the height of the tower with the height of the step at which the t

CF 915 D 拓扑排序

#include <bits/stdc++.h> using namespace std; const int maxn = 1e5 + 10; const int mod = 142857; int t,n,m,k,x,u,v,w,num,flag; vector<int> G[maxn]; int inDeg[maxn], ruDeg[maxn]; int virus[maxn]; queue<int> q; bool topSort() { num=0; whil

Matplotlib初体验

为一个客户做了关于每个差异otu在时间点上变化的折线图,使用python第一次做批量作图的程序,虽然是很简单的折线图,但是也是第一次使用matplotlib的纪念. ps:在第一个脚本上做了点小的改动,加上了分类信息作为图的标题,加上网格便于对照y轴丰度值,x轴的名称更加接近样品的实际名称. 1 from __future__ import division 2 import numpy as np 3 import matplotlib.pyplot as plt 4 from matplot

[转]C++编写Config类读取配置文件

C++代码   //Config.h #pragma once #include <string> #include <map> #include <iostream> #include <fstream> #include <sstream> /* * \brief Generic configuration Class * */ class Config { // Data protected: std::string m_Delimiter

部署Sendmail

简介: 如何在Linux环境中配置sendmail,以及出错了如何修复. 配置文件1:/etc/hosts 127.0.0.1 should go on the first line. The first entry for 127.0.0.1 MUST be localhost.localdomain The last entry for 127.0.0.1 SHOULD be the hostname, ex: srv-etam-cn-web1 The first entry for the

已开发程序查询

REPORT zmail. TABLES: trdir, tstc. DATA: BEGIN OF gs_data, sel TYPE boolean, " 用于选择多行 name TYPE trdir-name, " 程序名 subc TYPE trdir-subc, " 程序类型 rstat TYPE trdir-rstat, " 状态 tcode TYPE tstc-tcode, " 事务码 ttext TYPE tstct-ttext, "

CF 412 D Giving Awards(拓扑排序)

The employees of the R1 company often spend time together: they watch football, they go camping, they solve contests. So, it's no big deal that sometimes someone pays for someone else. Today is the day of giving out money rewards. The R1 company CEO