Educational Codeforces Round 94

A题:String Similarity

题意:给定一个长为2n-1的01字符串S,要求你构造一个长为n的字符串,使得该字符串与 s[1..n], s[2..n+1], s[3..n+2], ..., s[n..2n−1].至少存在一位相等

Solution

观察到每个字符串都有s[n],因此只需要将字符串全部改为s[n]即可

Code

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

signed main()
{
    ios::sync_with_stdio(0); cout.tie(0); cin.tie(0);
    int t; cin >> t;
    while (t--)
    {
        int n; cin >> n;
        string s; cin >> s;
        s = ' ' + s;
        for (int i = 1; i <= n; i++)
            cout<<s[n];
        
        cout << endl;
    }
    return 0;
}

B题:RPG Protagonist

题意:两个背包有不同容量,给出两种物品的数量,重量和价值,问最多能带走两种物品的最大数量总和

Solution

刚开始觉得是背包,想了很久但是数据范围太大了,后面看题解才知道。

枚举第一个背包买第一种物品的数量,则第一个背包买第二种物品的数量便已经固定,对于第二个背包(先使得第一个物品重量最小),由于只考虑数量最多,所以优先购买重量最小的,如果第一个卖完了,才购买第二个

Code

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

int v1, v2, n1, n2, w1, w2;
int num2, num3, num4;
int ans;

signed main()
{
    ios::sync_with_stdio(0); cout.tie(0); cin.tie(0);
    int t; cin >> t;
    while (t--)
    {
        cin >> v1 >> v2 >> n1 >> n2 >> w1 >> w2;
        ans = -9;
        if (w1 > w2)swap(n1, n2), swap(w1, w2);
        for (int i = 0; i <= n1; i++)
        {
            if (i * w1 > v1)break;
            num2 = min(n2, (v1 - i * w1) / w2);
            num3 = min(n1 - i, v2 / w1);
            num4 = min(n2 - num2, (v2 - num3 * w1) / w2);
            ans = max(ans, i + num2 + num3 + num4);
        }
        cout << ans << endl;
    }
    return 0;
}

C题:Binary String Reconstruction

C题难度低于B题,属于基本的模拟题

Code

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


signed main()
{
    ios::sync_with_stdio(0); cout.tie(0); cin.tie(0);
    int t; cin >> t;
    while (t--)
    {
        int p = 0;
        string s; cin >> s;
        int x; cin >> x;
        s = ' ' + s;
        string s1(s.size() - 1, '1');
        s1 = ' ' + s1;
        for (int i = 1; i < s.size(); i++)
        {
            if (i - x < 1 && i + x >= s.size() && s[i] == '1')
            {
                p = 1;
                break;
            }
            if (s[i] == '0')
            {
                if (i - x >= 1)s1[i - x] = '0';
                if (i + x < s.size())s1[i + x] = '0';
            }
        }
        for (int i = 1; i < s.size(); i++)
        {
            if (s[i] == '1')
            {
                int k = 0;
                if (i - x >= 1)
                    if (s1[i - x] == '1')k = 1;
                if (i + x < s.size())
                    if (s1[i + x] == '1')k = 1;
                if (!k)
                {
                    p = 1;
                    break;
                }
            }
        }
        if (p)cout << -1 << endl;
        else
        {
            for (int i = 1; i < s.size(); i++)cout << s1[i];
            cout << endl;
        }
    }
    return 0;
}

D题:Zigzags

题意:给出一个序列a,问序列a满足条件的四元组的数量

Solution

四元组枚举中间两个变量即可,每次枚举,由乘法原理可得出当前中间变量满足条件的四元组的数量为中间第一个变量左边等于中间第二个变量的值的数量*中间第二个变量右边等于中间第一个变量的值的数量,注意到数字大小很小,因此只需要开一个前缀数量数组记录即可,从左到右每次对每个位置的左边的所有值进行一次记录,右边的数量可由前缀相减得到

Code

#include<bits/stdc++.h>
using namespace std;
#define int long long
int num[3030][3030];
int a[3030];
int ans;
int n;

void cal(int x, int y)
{
    ans += num[x - 1][a[y]] * (num[n][a[x]] - num[y][a[x]]);
}

signed main()
{
    ios::sync_with_stdio(0); cout.tie(0); cin.tie(0);
    int t; cin >> t;
    while (t--)
    {
       cin >> n;
       ans=0;
        for (int i = 1; i <= n; i++)
            for (int j = 1; j <= n; j++)
                num[i][j] = 0;
        for (int i = 1; i <= n; i++)
        {
            cin >> a[i];
            for (int j = 1; j <= n; j++)
                num[i][a[j]] = num[i - 1][a[j]];
            num[i][a[i]]++;
        }
  
        for (int i = 2; i <= n - 2; i++)
            for (int j = i + 1; j <= n - 1; j++)
                cal(i, j);
        cout << ans << endl;
    }
    return 0;
}

与该题类似,但解决办法却不一样的:Acwing 三元组

Solution

与之不同的是,每个数都很大,如果只是数字大但个数少,我们可以用unordered_map记录,但该题个数也很多,所以必须考虑新的方法。

由于我们只需要纪录中间变量的前一个和后一个变量的数量,我们可以分别从前,从后遍历一次,每一次用unorderded_map纪录每个数字的的数量,若出现中间变量(即可以整除k),此时的a[i]/k或者a[i]*k的数量就是其左变量或者右变量的数量,用两个数组l[],r[]记录即可,最后由乘法原理计算即可

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N = 2e5 + 10;
int l[N], r[N];
int a[N];
signed main()
{
    ios::sync_with_stdio(0); cout.tie(0); cin.tie(0);
    int n, k; cin >> n >> k;
    unordered_map<int, int>num;
    unordered_map<int, int>num1;
    for (int i = 1; i <= n; i++)
    {
        cin >> a[i];
        if (a[i] % k == 0)
            l[i] = num[a[i] / k];
        num[a[i]]++;
    }
    for (int i = n; i>=1; i--)
    {
        if (a[i] % k == 0)
            r[i] = num1[a[i]*k];
        num1[a[i]]++;
    }
    int ans = 0;
    for (int i = 1; i <= n; i++)
    {
        ans += (l[i] * r[i]);
    }
    cout << ans;
    return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值