Codeforces Round #849 (Div. 4)(A-G1)

目录

A.Codeforces Checking

B.Following Directions

C.Prepend and Append

D.Distinct Split


A.Codeforces Checking

 题意:

给我们若干个字母,让我们去判断当前的字母是否出现在“codeforces”中,如果出现输出“Yes”否者输出“No”(大小写无所谓)。

简单题,直接暴力做就行

#include <bits/stdc++.h>

using namespace std;
#define endl '\n';
const int N = 1e5 + 10;
typedef long long ll;
typedef pair<int, int> PII;

void solve()
{
    string str = "codeforces";
    char ch;
    cin >> ch;
    if (str.find(ch) == -1)
    {
        cout << "NO" << endl;
        return;
    }
    else
        cout << "Yes" << endl;
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.tie(0);
    int n;
    cin >> n;
    while (n--)
    {
        solve();
    }
    return 0;
}
/*
10 a b c d e f g h i j

NO NO YES YES YES YES NO NO NO NO
 */

B.Following Directions

题意:

给我们若干字符串,每个字符串由L,R,U,D四个字母构成(每个字母代表的是向不同的方向移动),问我们在移动的过程中是否会经过(1,1)这个点。

简单题,直接暴力做就可以,不过我们可以简单的优化一下,例如向上走我们可以x+1,向左走y+1,像这个一样简单的写一下。

#include <bits/stdc++.h>

using namespace std;
#define endl '\n';
const int N = 1e5 + 10;
typedef long long ll;
typedef pair<int, int> PII;

void solve()
{
    int n;
    cin >> n;
    char ch;
    int x = 0, y = 0, flag = 0;
    for (int i = 0; i < n; i++)
    {
        cin >> ch;
        if (ch == 'U')
            x = x + 1;
        if (ch == 'R')
            y = y + 1;
        if (ch == 'D')
            x = x - 1;
        if (ch == 'L')
            y = y - 1;
        if (x == 1 && y == 1)
            flag = 1;
    }
    if (flag == 1)
        puts("Yes");
    else
        puts("No");
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.tie(0);
    int n;
    cin >> n;
    while (n--)
    {
        solve();
    }
    return 0;
}

 C.Prepend and Append

题意:

给我们若干组只有0和1组成的字符串。这些字符串是经过若干的变换后形成的,变换指的是我们可以进对最初的字符串一端加上0,一段加上1。现在我们需要求出最初的字符串有多长。

我们可以利用双指针的思想,两头一块枚举,如果当前的头尾指针上的元素不同,那么头指针左移一位,尾指针右移一位,长度-2,一直枚举到头尾指针重合或者头尾指针的元素相等的时候停止移动。代码如下:

#include <bits/stdc++.h>

using namespace std;
#define endl '\n';
const int N = 1e5 + 10;
typedef long long ll;
typedef pair<int, int> PII;

void solve()
{
    int n;
    cin >> n;
    char str[N];
    for (int i = 0; i < n; i++)
        cin >> str[i];

    int l = 0, r = n - 1, len = n;
    while (str[l] != str[r] && l <= r)
        l++, r--, len -= 2;
    cout << len << endl;
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.tie(0);
    int n;
    cin >> n;
    while (n--)
    {
        solve();
    }
    return 0;
}

D.Distinct Split

 题意:

给我们若干的字符串,每个字符串是由小写字母组成的。我们定义f(x)为一个字符串中含有字母的个数,现在我们需要给出一个分界线,使得我们原来的字符串在分割线后,分割线左右两个字符串的f(左)+f(右)最大,问我们这个最大的值是多少。

思考:

开始的时候我先用暴力想了一下,每次去枚举不同的分割线,用res去存储当前最大的f(左)+f(右),不断去更新,不过我有看了一下数据范围1e4组数据,每组要枚举2e5次,每次要在计算左右两边的字母种类,暴力去做一定会超时的,那么我们就要去优化这个暴力的做法。看这个题我们把字符串分成了两部分,我由此联想到了前缀和的算法,用一个额外的数据结构去存储字符种类的前缀和和后缀和,这样我们在计算每次分割线的时候只需要去计算前缀和和后缀和的和就行了,就不需要过多的暴力了。(别看我说的轻松我写的时候改了好久呢,因为我傻了,忘了后缀和怎么算了,算法之路漫长!)

#include <bits/stdc++.h>

using namespace std;
const int N = 2e5 + 10;
int num[26];

struct data
{
    int cnt[26];
    int kind;
} q[N];

void solve()
{
    int n;
    cin >> n;
    string str;
    cin >> str;
    set<char> s;
    for (int i = 0; i < n; i++)
    {
        s.insert(str[i]);
        num[str[i] - 'a']++;
        for (int j = 0; j < 26; j++)
            q[i].cnt[j] = num[j];
        q[i].kind = s.size();
    }

    int res = 0;
    for (int i = 0; i < n; i++)
    {
        int p = 0;
        for (int j = 0; j < 26; j++)
            if (q[n - 1].cnt[j] > q[i].cnt[j])
                p++;
        res = max(res, p + q[i].kind);
    }

    cout << res << endl;
}

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.tie(0);

    int t;
    cin >> t;

    while (t--)
    {
        solve();
    }

    return 0;
}

但是后来我看到了jiangly的代码,再一次被大佬的代码给震惊了,这是看过大佬写的代码后仿写的,简洁太多了,大家有能力的可以看一下大佬的每一次的代码,每次看大佬我都会有不少的收获。jiangly tql !!!

#include <bits/stdc++.h>

using namespace std;
const int N = 2e5 + 10;
int num[26];

void solve()
{
    int n;
    cin >> n;

    string str;
    cin >> str;

    vector<int> l, r;
    set<char> s;
    for (int i = 0; i < n; i++)
    {
        s.insert(str[i]);
        l.push_back(s.size());
    }
    s.clear();
    for (int i = n - 1; i >= 0; i--)
    {
        s.insert(str[i]);
        r.push_back(s.size());
    }

    int res = 0;
    for (int i = 0; i < n - 1; i++)
        res = max(res, l[i] + r[n - i - 2]);
        
    cout << res << endl;
}

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.tie(0);

    int t;
    cin >> t;

    while (t--)
    {
        solve();
    }

    return 0;
}

E.Negatives and Positives

 题意:给我们一个长度为N的数组,在经过若干次变换后,问我们所能求得的最大值是多少?

变换的含义是选择两个相邻的元素,使其变成他自己的相反数。

思路介绍:这个题本质上就是求一个最大值,这个最大值一定是小于等于所有数的绝对值加和。那么这个变换如何能够让我们已有的数组取得最大的值。由于我们可以翻转任意两个相邻两个元素的值,那么当这个数组中有且只有奇数个负数时,我们就可以通过上述的操作将绝对值最小的元素变成负数,其余的所有数都可以变成正数,如下图:经过两次变换就可以变成仅有一个负数和其余都是正数的情况,那么我们就尽量将最小的数变成负数,其余的数都变成正数,这样我们的值取得便是最大值,除此之外,如果有偶数个负数,那么我们经过若干次变换之后就可以将所有的数都变成正数,就不用担心那个最小值的问题了。

代码:

#include <bits/stdc++.h>

using namespace std;
const int N = 2e5 + 10;
typedef long long ll;
void solve()
{
    ll n, sum = 0, cnt = 0;
    cin >> n;
    vector<ll> a(n);
    for (int i = 0; i < n; i++)
    {
        cin >> a[i];
        if (a[i] <= 0)
            cnt++, a[i] = abs(a[i]);
        sum += abs(a[i]);
    }
    sort(a.begin(), a.end());

    if (cnt % 2 == 0)
    {
        cout << sum << endl;
    }
    else
    {
        cout << sum - abs(a[0]) * 2 << endl;
    }
}
int main()
{

    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.tie(0);

    int n;
    cin >> n;
    while (n--)
    {
        solve();
    }

    return 0;
}

 F.Range Update Point Query

题意:

给我们一个长度为n的数组我们对其进行若干次操作,请给出经过操作后的所询问的数值。操作共有两个:

1.求出a[l]---a[r]之间每一个数各个数位上的和,并用其覆盖原数。

2.给出一个x,请你输出a[x]。

 这个题我赛时并没有做出来,后期看了大佬的代码后自己才补出来的。

具体的思路:

我们可以知道任何一个n(1<n<1e9)他至多可以进行三次数位求和,其次一个一位数无论怎么求其数位和,他的值都是不变的。那么我们可以用一个set来存储一下这些需要求数位和的数的下标,然后我们在进行第一种操作的时候我们就可以只对那个需要进行操作的数进行操作,这里可以借用lower_bound函数二分来加速我们的查找(set是有序的),每次找到当前需要进行操作的数,对其进行操作,并将其删除,如果他还是大于9,那么我们将他的下标加入到set中去,进行下一次操作。

代码:

#include <bits/stdc++.h>

using namespace std;
const int N = 2e5 + 10;
typedef long long ll;

int sum(int x)
{
    int res = 0;
    while (x)
    {
        res += x % 10;
        x /= 10;
    }
    return res;
}
void solve()
{
    int n, q;
    cin >> n >> q;
    vector<int> a(n);
    set<int> st;
    for (int i = 0; i < n; i++)
    {
        cin >> a[i];
        if (a[i] > 9)
            st.insert(i);
    }

    while (q--)
    {
        int type;
        cin >> type;
        if (type == 1)
        {
            int l, r;
            cin >> l >> r;
            l--, r--; // 对其下标
            int now = l;
            while (!st.empty())
            {
                auto it = st.lower_bound(now);
                if (it == st.end() || *it > r)
                    break;
                a[*it] = sum(a[*it]);
                int x = *it;
                st.erase(it);
                if (a[x] > 9)
                    st.insert(x);
                now = x + 1;
            }
        }
        else
        {
            int x;
            cin >> x;
            cout << a[x - 1] << endl;
        }
    }
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.tie(0);

    int n;
    cin >> n;
    while (n--)
    {
        solve();
    }

    return 0;
}

G1.Teleporters (Easy Version)

这个题就是和题意一样的,估计这个题大家是没做到,并不是没有做,大家可以看看这个题

#include <bits/stdc++.h>

using namespace std;
#define endl '\n';
const int N = 1e5 + 10;
typedef long long ll;
typedef pair<int, int> PII;

void solve()
{
    int n, val;
    cin >> n >> val;
    vector<int> a(n);
    for (int i = 0; i < n; i++)
    {
        cin >> a[i];
        a[i] += i + 1;
    }

    sort(a.begin(), a.end());
    int res = 0;
    for (int i = 0; i < n; i++)
    {
        if (a[i] <= val)
        {
            res++;
            val -= a[i];
        }
        else
            break;
    }
    cout << res << endl;
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.tie(0);
    int n;
    cin >> n;
    while (n--)
    {
        solve();
    }
    return 0;
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值