【CF题解】Codeforces Round #710 (Div. 3)

A Strange Table

有两个M x N的矩阵,一个逐行摆放,一个逐列拜访。给定一个数x,求x在逐列摆放的矩阵中的位置(i,j)在逐行摆放的矩阵中对应的数值

#include <cstdio>
using namespace std;
typedef long long ll;

int main()
{
    int t;
    cin >> t;
    while (t--)
    {
        ll n, m, x;
        cin >> n >> m >> x;
        x--;
        cout << x % n * m + x / n + 1 << endl;
    }
    return 0;
}

B Partial Replacement

有一个长度为 nn 的字符串只包含.和*
现在要求你把其中的第一个和最后一个必须变成x
其他的可以选择其中一些变成x
问最少需要把几个
变成x使得相邻的两个x之间距离不超过 kk


将第一个和最后一个标记为l和r
如果l==r说明只有一个
则输出1;
否则, 从l+k开始到l找到第一个为*的点变化,并将l改为这个点

#include <iostream>
using namespace std;
const int maxn = 200;
typedef long long ll;
char a[maxn];
int main()
{
    int t;
    cin >> t;
    while (t--)
    {
        int n, k;
        cin >> n >> k;
        cin >> a + 1;
        int l, r;
        for (int i = 1; i <= n; i++)
            if (a[i] == '*')
            {
                l = i;
                break;
            }
        for (int i = n; i >= 1; i--)
            if (a[i] == '*')
            {
                r = i;
                break;
            }
        int ans = 2;
        if (l == r)
            ans--;
        while (r - l > k)
        {
            for (int i = k;; i--)
                if (a[l + i] == '*')
                {
                    l += i;
                    ans++;
                    break;
                }
        }
        cout << ans << endl;
    }
    //system("pause");
}

C Double-ended Strings

给出两个字符串 a, ba,b 每次可以删掉 aa 或 bb 的第一个字符或最后一个字符,问最少删几个字符使得两个字符串相等 T \leq1 00T≤100 组测试数据

#include <bits/stdc++.h>
using namespace std;
const int maxn = 25;
int main()
{
    int t;
    cin >> t;
    while (t--)
    {
        char a[maxn], b[maxn];
        cin >> a >> b;
        int maxx = -1;
        for (int i = 0; i < strlen(a); i++)
            for (int j = 0; j < strlen(b); j++)
            {
                int res = 0;
                for (int k = 0; k < strlen(a) && k < strlen(b); k++)
                {
                    if (a[k + i] == b[k + j])
                        res++;
                    else
                        break;
                }
                maxx = max(maxx, res);
            }
        cout << strlen(a) + strlen(b) - 2 * maxx << endl;
    }
    return 0;
}

D Epic Transformation

给出一个长度为 nn 整数序列 aa,每次可以任选两个不相同的数都删掉,问最少剩下几个数


如果最大的数量maxx不超过剩下数量的一半,即2maxx>n,那么答案只能为0(偶数个,恰好全部删除)或1(奇数个,恰好剩下一个)
如果超过剩下数量的一半,那么答案为maxx-(n-maxx),即2
maxx-n

#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e6 + 10;

int main()
{
    int t;
    cin >> t;
    while (t--)
    {
        int n;
        cin >> n;
        map<int, int> m;
        int maxx = -1;
        for (int i = 0; i < n; i++)
        {
            int x;
            cin >> x;
            maxx = max(maxx, ++m[x]);
        }
        if (2 * maxx >= n)
            cout << 2 * maxx - n << endl;
        else
            cout << (n & 1 ? 1 : 0) << endl;
    }
    return 0;
}

E Restoring the Permutation

有一个长度为 n 的排列 p,现在给出排列 p 的前缀最大值序列,求字典序最小和最大的排列 p


设前缀最大值序列为a,当a[i]!=a[i-1] 的时候,显然a[i]必须大于a[i-1],则此时,必有p[i]==a[i](想一想,为什么)

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<set>
 
using namespace std;
 
typedef long long LL;
 
const int N = 200010;
 
int n;
int a[N];
 
int main()
{
    int t;
    cin>>t;
    while(t --)
    {
        scanf("%d", &n);
        for(int i = 1; i <= n; i ++)  scanf("%d", &a[i]);
 
        set<int> S;
        for(int i = 1; i <= n; i ++)  S.insert(i);
        for(int i = 1; i <= n; i ++)
        {
            if(a[i] != a[i - 1])
            {
                printf("%d ", a[i]);
                S.erase(a[i]);
            }
            else
            {
                auto it = S.begin();
                printf("%d ", *it);
                S.erase(it);
            }
        }
        puts("");
 
        for(int i = 1; i <= n; i ++)  S.insert(i);
        for(int i = 1; i <= n; i ++)
        {
            if(a[i] != a[i - 1])
            {
                printf("%d ", a[i]);
                S.erase(a[i]);
            }
            else
            {
                auto it = S.lower_bound(a[i] + 1);
                it --;
                printf("%d ", *it);
                S.erase(it);
            }
        }
        puts("");
    }
    return 0;
}

F Triangular Paths

有一个 nn 行,第 i 行有 i 个元素的下三角矩阵
当 (i+j)%2=0 时 (i, j)(i,j) 有一条通往 (i + 1, j)(i+1,j) 的边,否则 (i, j)(i,j) 有一条通往 (i + 1, j + 1)(i+1,j+1) 的边
可以花费 11 的代价令某一个点的出边在抵达 (i + 1, j)(i+1,j) 和 (i + 1, j + 1)(i+1,j+1) 之间互换
现在给出一个 nn 个点的点集,求从(1, 1)(1,1)出发最少花费多少代价可以遍历到这些点


在这里插入图片描述

#include <bits/stdc++.h>
using namespace std;
typedef pair<int, int> pii;
const int maxn = 2e5 + 10;
pii p[maxn];

int main()
{
    int t;
    cin >> t;
    while (t--)
    {
        int n;
        cin >> n;
        for (int i = 1; i <= n; i++)
            cin >> p[i].first;
        for (int i = 1; i <= n; i++)
            cin >> p[i].second;
        p[0].first = p[0].second = 1;
        sort(p + 1, p + n + 1);
        int ans = 0;
        for (int i = 1; i <= n; i++)
        {
            //如果dx-dy==0 则 只向右下走
            //如果x+y偶数 ans+=dx;
            int dx = p[i].first - p[i - 1].first, dy = p[i].second - p[i - 1].second;
            int t = dx - dy;
            if (!t)
            {

                ans += ((p[i].first + p[i].second) % 2 == 0) ? dx : 0;
            }
            //如果dx-dy!=0 则既有向下走 也有向右下走
            //如果x+y为奇数,只能向右下走,向下走多少次 ans+多少;
            else
            {
                if ((p[i - 1].first - p[i - 1].second) % 2 == 0)
                {
                    ans += (t >> 1);
                }
                else
                    ans += (t + 1) >> 1;
            }
        }
        cout << ans << endl;
    }
    //system("pause");
    return 0;
}

G Maximize the Remaining String

给定一个字符串s,求一个字典序最大的字符串t;t和s具有相同的集合。


集合中元素从大到小枚举,如果满足题意(填入元素c后,剩下字符和剩下集合依然成立) 则填入元素c

主程序

int slen(string s)
{
    sort(s.begin(), s.end());
    return unique(s.begin(), s.end()) - s.begin();
}

void solve()
{
    string s;
    cin >> s;
    //求s集合的大小
    int m = slen(s);
    string t;
    //用字符串s初始化集合,从大到小排列。
    set<char, greater<int>> used(s.begin(), s.end());
    while (m > 0)
    {
    	//每次枚举集合中最大的元素
        for (auto c : used)
        	//如果符合条件,则将c放进t,并从集合中删除c
            if (check(s, c) == m - 1)
            {
                t += c;
                used.erase(c);
                //从字符串s中删除c字符
                s = Delete(s, c);
                break;
            }
        m--;
    }
    cout << t;
}

条件判定

//检验字符c是否符合条件
int check(string s, char c)
{
    string t;
    bool flag = false;
    //扫描字符串s
    for (auto e : s)
    	//如果遇到字符c,则删去字符c(不copy到t中)
        if (e == c)
            flag = true;
        //(把出现在c后的字符copy到t中)
        else if (e != c && flag)
            t += e;
    return slen(t);
}

string Delete(string s, char c)
{
    string t;
    bool flag = false;
    for (auto e : s)
        if (e == c)
            flag = true;
        else if (e != c && flag)
            t += e;
    return t;
}

完整代码

#include <bits/stdc++.h>
using namespace std;

int slen(string s)
{
    sort(s.begin(), s.end());
    return unique(s.begin(), s.end()) - s.begin();
}

int check(string s, char c)
{
    string t;
    bool flag = false;
    for (auto e : s)
        if (e == c)
            flag = true;
        else if (e != c && flag)
            t += e;
    return slen(t);
}

string Delete(string s, char c)
{
    string t;
    bool flag = false;
    for (auto e : s)
        if (e == c)
            flag = true;
        else if (e != c && flag)
            t += e;
    return t;
}

void solve()
{
    string s;
    cin >> s;
    int m = slen(s);
    string t;
    set<char, greater<int>> used(s.begin(), s.end());
    while (m > 0)
    {
        for (auto c : used)
            if (check(s, c) == m - 1)
            {
                t += c;
                used.erase(c);
                s = Delete(s, c);
                break;
            }
        m--;
    }
    cout << t;
}

int main()
{
    int t;
    cin >> t;
    while (t--)
    {
        solve();
    }
    system("pause");
}
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值