Educational Codeforces Round 115 (Rated for Div. 2)

A Computer Game

题目大意

给定两个长度为n的01串,0能通过,1不能通过,问能否从(1, 1)走到(2, n)

主要思路

只要从1到n的任意位置不存在上下两个全是1的情况即可

AC代码
#include <bits/stdc++.h>

#define int long long
using namespace std;
#define debug(a) cout << #a << " = " << a << endl;
#define x first
#define y second
typedef long long ll;
const int N = 500010, mod = 1e9+7;

int n, m;

signed main(void)
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    
    int T;
    cin >> T;
    while(T--)
    {
        cin >> n;
        bool flag = true;
        string s[10];
        for(int i = 1; i <= 2; i++)
        {
            cin >> s[i];
        }
        
        if(s[1][0] == 1) flag = false;
        else
        {
            for(int i = 0; i < n; i++)
            {
                if(s[1][i] == '1' && s[2][i] == '1') flag = false;
            }
        }
        
        if(flag) cout << "YES" << endl;
        else cout << "NO" << endl;
    }
    return 0;
}

B Groups

题目大意

给定n个人,每个人都有想去的的周几的课,让你把这些学生分成人数相同的两队,并且每队的学生都愿意去某一节课,且两队去的课不能相同

主要思路

暴力枚举每一队选择哪两天,假设第一队选择i,第二队选择j

首先判断出愿意在i且不愿意在j的人数cnti,愿意在j不愿意在i的人数cntj,以及即愿意在i也愿意在j的人数cnt,如果有人既不愿意在i也不愿意在j那么不能分成两队一定不合法

其次我们只要让cnt分给cnti和cntj让这两个值相等即可

假设cnti + cnt < cntj || cntj + cnt < cnti这样一定不能让cnti和cntj相等,其余情况均可

AC代码
#include <bits/stdc++.h>

#define int long long
using namespace std;
#define debug(a) cout << #a << " = " << a << endl;
#define x first
#define y second
typedef long long ll;
const int N = 1010, mod = 1e9+7;

int n, m;
int a[N][10];
int st[N];

bool check(int x, int y)
{
    int cntx = 0, cnty = 0, cnt = 0;
    for(int i = 1; i <= n; i++)
    {
        if(a[i][x] && !a[i][y]) cntx++;
        else if(!a[i][x] && a[i][y]) cnty++;
        else if(a[i][x] && a[i][y])
        {
            cnt++;
        }
        else return false;
    }
    if(cntx + cnt < cnty || cnty + cnt < cntx) return false;
    else return true;
}

signed main(void)
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    
    int T;
    cin >> T;
    while(T--)
    {
        cin >> n;
        for(int i = 1; i <= n; i++)
        {
            for(int j = 1; j <= 5; j++)
            {
                cin >> a[i][j];
            }
        }
        
        bool flag = false;
        for(int i = 1; i <= 5; i++)
        {
            for(int j = i + 1; j <= 5; j++)
            {
                if(check(i, j)) flag = true; 
            }
        }
        
        if(flag) cout << "YES" << endl;
        else cout << "NO" << endl;
    }
    return 0;
}

C Delete Two Elements

题目大意

给定k个数,让你在k个数中任选两个数使其剩下的k-2个数的平均值与k个数的平均值相同,问有多少种选法

主要思路

首先假设n个数平均值为k,k * 2为任选的两个数的和

  • 假设这个数不为整数,那么一定返回0,因为输入n个数都为整数,(a + b) / 2 == sum / n,于是sum * 2 / n == a + b,由于a + b是整数,所以(sum * 2) % n == 0
  • 然后我们对数组记录每个数出现的次数,然后排序+去重
  • 遍历排序去重后的数组,对每个数二分找两个数的和与k*2相等的数,加上两个数个数的乘积即可
AC代码
#include <bits/stdc++.h>

#define int long long
using namespace std;
#define debug(a) cout << #a << " = " << a << endl;
#define x first
#define y second
typedef long long ll;
const int N = 200010, mod = 1e9+7;
const double eps = 1e-8;

int n, m;

signed main(void)
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    
    int T;
    cin >> T;
    while(T--)
    {
        unordered_map<int, int> st;
        cin >> n;
        vector<int> a(n);
        int sum = 0;
        for(int i = 0; i < n; i++) cin >> a[i], sum += a[i], st[a[i]]++;
        sort(a.begin(), a.end());
        a.erase(unique(a.begin(), a.end()), a.end());
        //debug(a.size())
        double k = sum * 1.0 / n;
        if((sum * 2) % n != 0)
        {
            cout << 0 << endl;
            continue;
        }
        
        int ans = 0;
        for(int i = 0; i < a.size(); i++)
        {
            int l = 0, r = a.size() - 1;
            while(l < r)
            {
                int mid = l + r >> 1;
                if((a[i] + a[mid]) * 1.0 / 2 >= k) r = mid;
                else l = mid + 1;
            }
            if((a[i] + a[l]) == k * 2)
            {
                if(a[i] != a[l]) ans += st[a[i]] * st[a[l]], st[a[i]] = 0, st[a[l]] = 0;
                else ans += st[a[i]] * (st[a[i]] - 1) / 2, st[a[i]] = 0;
            }
        }
        cout << ans << endl;
    }
    return 0;
}
D Training Session
题目大意

给定n对(x, y),问从中选出3对且这3对不存在x有相同且y有相同,问能选出多少组合

主要思路

正着计算不好计算我们考虑反着算,先计算出n个数中任选3个数情况是n * (n - 1) * (n - 2) / 6,然后减去选出的3各种x有相同且y有相同的情况

我们先统计出每一个x出现的次数和每一个y出现的次数,然后从1开始遍历,答案每次减去当前遍历到的x和当前遍历到的y的(x - 1)*(y - 1)的乘积,每次要除去自己本身,在其他x中任取一个以及在其他y中任取一个,由于不存在两队x和y相同,所以不存在重复情况

AC代码
#include <bits/stdc++.h>

#define int long long
using namespace std;
#define debug(a) cout << #a << " = " << a << endl;
#define x first
#define y second
typedef long long ll;
const int N = 200010, mod = 1e9+7;

int n, m;
pair<int, int> a[N];

signed main(void)
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    
    int T;
    cin >> T;
    while(T--)
    {
        unordered_map<int, int> mpx, mpy;
        
        cin >> n;
        for(int i = 0; i < n; i++)
        {
            cin >> a[i].x >> a[i].y;
            mpx[a[i].x]++, mpy[a[i].y]++;
        }
        
        int ans = n * (n - 1) * (n - 2) / 6;
        for(int i = 0; i < n; i++)
        {
            ans -= (mpx[a[i].x] - 1) * (mpy[a[i].y] - 1);
        }
        cout << ans << endl;
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值