UVA - 1611 Crane 推理 + 贪心

题目大意:输入一个1-n的排列,要求经过操作将其变换成一个生序序列。操作的规则如下

每次操作时,可以选一个长度为偶数的连续区间,交换前一半和后一半

提示:2n次操作就足够了

解题思路:这句提示是关键,2n次操作,表明每个数最多只需要两次操作。

应该从左到右依次操作过去,先将前面的数安定好了,就可以不用管前面的数了

假设操作到第i个位置,而i这个数刚好在pos这个位置上,现在就要判断一下能否直接将pos上的i经过操作调到i这个位置上

如果 i + (pos - i) * 2 - 1 <= n 就表示可以一次操作完成

在上面条件不成立的情况下,又分为两种情况

一种是pos和i的距离是奇数的情况:那么就直接将[i,pos]这个区间的值进行交换即可

另一种是距离为偶数的情况,那就把[i+1,pos]这个区间的值进行交换即可

参考了别人的代码:

#include<cstdio>
#include<algorithm>
#include<vector>
#include<iostream>
using namespace std;
typedef pair<int,int> Pair;
#define maxn 10010
int num[maxn];

void change(int l, int r) {
    for(int i = l, j = l + (r - l + 1) / 2; j <= r; j++, i++)
        swap(num[i],num[j]);
}
int main() {
    int test, n;
    scanf("%d", &test);
    while(test--) {
        scanf("%d", &n);
        for(int i = 1 ; i <= n; i++)
            scanf("%d", &num[i]);
        vector<pair<int,int> > ans;
        for(int i = 1; i <= n; i++) {
            int pos;
            for(int j = i; j <= n; j++)
                if(num[j] == i) {
                    pos = j;
                    break;
                }
            if(pos == i)
                continue;
            if(i + 2 * (pos - i) - 1 <= n) {
                ans.push_back(Pair(i,i + 2 * (pos - i) - 1));
                change(i, i + 2 * (pos - i) - 1);
            }
            else {
                if((pos - i) % 2) {
                    ans.push_back(Pair(i, pos));
                    change(i,pos);
                }
                else {
                    ans.push_back(Pair(i + 1, pos));
                    change(i + 1, pos);
                }
                i--;
            }
        }
        cout << ans.size() << endl;
        for(int i = 0; i < ans.size(); i++)
            printf("%d %d\n",ans[i].first, ans[i].second);
    }
    return 0;
}
时间: 2024-10-14 05:06:46

UVA - 1611 Crane 推理 + 贪心的相关文章

UVa 1611 Crane (构造+贪心)

题意:给定一个序列,让你经过不超过9的6次方次操作,变成一个有序的,操作只有在一个连续区间,交换前一半和后一半. 析:这是一个构造题,我们可以对第 i 个位置找 i 在哪,假设 i  在pos 位置,那么如果 (pos-i)*2+i-1 <= n,那么可以操作一次换过来, 如果不行再换一种,如果他们之间元素是偶数,那么交换 i - pos,如果是奇数,交换 i - pos+1,然后再经过一次就可以换到指定位置. 代码如下: #pragma comment(linker, "/STACK:1

Uva 1611 Crane

Thinking about it: 对于一个长度为N的序列,最大的数字为N,那么如果要将它放回到第N个位置,那么最多需要2步. 先用例子简单证明一下: 假设序列:1 2 3 6 5 4,当前最大数为6,需要和4交换位置,那么可以看作:* * * 6 * 4,因为6和4之间有一个数,而6之前有三个数,那么可以之间把6之后的部分,与6(包括)之前的     等长部分交换,可得 : 1 2 5 4 3 6,此时只需要一步,即可.   若如果,6之前的数 小于 6与4之间的数呢,如 1 6 2 3 4

UVA 1611 Crane 起重机

题意:给一个1~n排列,1<=n<=10000,每次操作选取一个长度为偶数的连续区间.交换前一半和后一半,使它变成升序. 题解:每次只要把最小的移动到最左边,那么问题规模就缩小了.假设当前区间为[l,r],不难发现,只要最小的数字在[l,l+(r+1-l)/2]这个区间内,一定可以通过一次交换把最小的数字移动到l处,否则,先一定可以一次交换把最小的数字移动到上述区间中. #include<bits/stdc++.h> using namespace std; const int m

uva 1611:Crane(构造 Grade D)

题目链接 题意: 一个序列,你可以选择其中偶数长度的一段,然后中间切开,左右两段交换.现给你一个1~n的某个排列,求一个交换方案,使得排列最终有序.(交换次数 < 9^6) 思路: 从左到右,依次把一个个数放到位.把一个数放到正确的位置,观察发现最多两步.第i个数,若现在的位置在 [i+1, (n+i)/2] 内,则可以一次到位.若在它右边,则可以通过一次,使得其到这个范围内. 代码: #include <cstdio> #include <cstring> #include

UVA 10317 - Equating Equations 贪心 dfs

UVA 10317 - Equating Equations 贪心 dfs ACM 题目地址:UVA 10317 - Equating Equations 题意: 给一个等式,但是这个等式不一定是正确的,要你对等式中的数字重新排序,使得等式成立.等式只有+和-,数字个数小于16. 分析: 以a + b - c = d - e为例子. 1. 我们把等式右边的各项都换到左边,a + b - c - d + e = 0 2. 把+项和-项放一起,就变成(a + b + e) - (c + d) = 0

UVA 12130 - Summits(BFS+贪心)

UVA 12130 - Summits 题目链接 题意:给定一个h * w的图,每个位置有一个值,现在要求出这个图上的峰顶有多少个.峰顶是这样定义的,有一个d值,如果一个位置是峰顶,那么它不能走到不大于该峰顶高度 - d的位置,如果满足这个条件下,并且无法走到更高的山峰,那么它就是峰顶 思路:利用贪心的策略,把所有点丢到优先队列,每次取出最高的峰值开始找,进行广搜,搜的过程中记录下最大值的点的个数,如果这个是峰顶,就加上这个数.判断是不是峰顶的方法为,如果广搜过程中,不会找到一个点的能到的最高峰

uva 11892 - ENimEN(推理)

题目链接:uva 11892 - ENimEN 题目大意:给定n堆石子的个数,两人轮流选择石子堆取石子,直到不能取为失败,附加条件,如果前一次操作,即队手的操作,没有将选中石子堆中的石子取完,那么当前操作者必须在该堆中取石子. 解题思路:只要有一个石子堆的个数大于2,那么先手就获得必胜态,可控.对于全是1的情况判断奇偶性. #include <cstdio> #include <cstring> #include <algorithm> using namespace

uva 1534 - Taekwondo(dp+贪心)

题目连接:uva 1534 - Taekwondo 题目大意:有两组什么东西,题目背景有点忘记了,就是给出两组数,两组个数分别为n,m,要求找出min(n,m)对数,每个数最多最多选一次,使得这min(n,m)对数ai,bi,ai-bi的绝对值之和最小. 解题思路:贪心,将两组数分别排序,然后dp[i][j]表示i对,匹配到j时候的最优解. #include <cstdio> #include <cstring> #include <cmath> #include &l

UVA1418-WonderTeam(推理+贪心)

题目链接 题意:有n支队伍比赛,每两支队伍打两场(主客场各一次),胜得3分,输不得分,平得1分.比赛结束之后会评选出一个梦之队,它满足如下条件:进球总数最多(不能并列),胜利场数最多(不能并列),丢球总数最少(不能并列).求梦之队的最低可能排名.一支得分为p的球队的排名等于等分严格大于p的球队的个数加1. 思路:其实3个限定条件只有胜利场数最多有用,因为梦之队可以在胜利场次大比分获胜,输的比赛都是1:0负于对手,其他两个就无关紧要了.要让梦之队排名尽量低,也就意味着让其得分尽量低.那么我们假设梦