CF大陆斗C战士(二)

C. Min Max Sort
题目大意

给定一个长度为n的排列p(长度为n的排列是一个长度为n的数组,其中从1到n的每个整数恰好出现一次)。您可以执行以下操作任意次数(可能为零):

  1. 选择两个不同的元素和y,并将它们从排列中删除;
  2. 将z和y的最小值插入到排列中,使其成为第一个元素;
  3. 将z和y的最大值插入到排列中,使其成为最后一个元素

问最少通过几次操纵可以使排列递增

题目分析

如果当前序列有序,则操作次数为0,当其无序的时候,我们要进一步进行思考

假设序列完全序,则我们最后一次的操作数必然为1n,倒数第二次选取的操作数为2n-1,以此类推则第一次的操作数为(n+1)/2(n+2)/2(由于向下取整的特性,使奇数也能正确找到中间数)

若每一对都要进行操作则需n/2次操作。从第一次的数对开始判断有多少对不用进行操作(即其位置一符合要求),则剩下的即为需要操作的次数。

code
#include<bits/stdc++.h>

using namespace std;

const int N = 2e5 + 10;

int n, m, k, t;
int f[N];

void solve()
{
    cin >> n;
    for(int i = 1; i <= n; i ++)f[i] = 0;

    for(int i = 1; i <= n; i ++)
    {
        cin >> m;
        f[m] = i;
    }

    int l = (n + 1) / 2, r = (n + 2) / 2;
    while(l > 0 && (l == r || (f[l] < f[l + 1] && f[r] > f[r - 1])))
        l --, r ++;

    cout << (n - (r - l) + 1) / 2 << "\n";
}

int main()
{
    cin >> t;
    while(t --) solve();
    return 0;
}

C. Skier
题目大意

滑雪者在雪地上滑行。它的运动可以用一串字符“s”、“N”、“w”、“E”来描述(分别对应南、北、西、东方向1米的运动)。我们知道,如果他沿着一条路径的一个以前未被访问的部分移动(即这段路径是第一次被访问的),那么这种移动的时间是5秒。如果他沿着之前访问过的路径段滚动(即,这段路径之前已经被他的路径覆盖过),则需要1秒。找出滑雪者滑完所有路径的时间。

题目分析

第一次经过某边贡献值为1,重复经过某边每次贡献值为5,判断每一个边是否重复经过累加相应的贡献值即可。

code
#include<bits/stdc++.h>

#define x first
#define y second

using namespace std;

typedef long long ll;
typedef pair<int, int>PII;

int n,  m, k, t;
string s;

void solve()
{
    cin >> s;
    map<pair<PII, PII>, int>q;

    ll ans = 0;
    int rx = 0, ry = 0;
    for(int i = 0; i < s.size(); i ++)
    {
        int nx = rx, ny = ry;

        if(s[i] == 'S') ry -= 1;
        else if(s[i] == 'N') ry += 1;
        else if(s[i] == 'W') rx -= 1;
        else if(s[i] == 'E') rx += 1;

        if(q[{{nx, ny}, {rx, ry}}]) ans ++;
        else ans += 5;

        q[{{nx, ny}, {rx, ry}}] ++;
        q[{{rx, ry}, {nx, ny}}] ++;
    }

    cout << ans << "\n";
}

int main()
{
    cin >> t;
    while(t --) solve();
    return 0;
}

C. Friends and Gifts
题目大意

有n个朋友想要互赠新年礼物。每个朋友只能送一份礼物,也只能收到一份礼物。朋友不能把礼物送给自己。对于每个朋友,f值都是已知的:如果第i个朋友不知道他想把礼物送给谁,填补fi=0处使得每个朋友只赠送一份礼物,也只收到一份礼物,并且没有朋友将礼物送给自己。保证初始信息不矛盾。如果有几个答案,你可以打印任何一个。

题目分析

因有一对一的前提,所以我们可以将未送出的和未收到的分别存储,再进行匹配,若碰到同一个人的情况,换一个匹配即可

code
#include<bits/stdc++.h>

using namespace std;

const int N = 2e5 + 10;

int n, m, k, t;
int a[N];
bool st[N];

void solve()
{
    vector<int>p, q;
    cin >> n;
    for(int i = 1; i <= n; i ++)
    {
        int u;
        cin >> u;
        a[i] = u;
        st[u] = true;
    }

    for(int i = 1; i <= n; i ++)
    {
        if(!a[i]) p.push_back(i);
        if(!st[i]) q.push_back(i);
    }

    for(int i = 0; i < p.size(); i ++)
    {
        if(p[i] == q[i])
            swap(q[i], q[(i + 1) % p.size()]);

    }
    for(int i = 0; i < p.size(); i ++)a[p[i]] = q[i];

    for(int i = 1; i <= n; i ++) cout << a[i] << " ";
    puts("");
}

int main()
{
    solve();
    return 0;
}

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值