Educational Codeforces Round 131 (Rated for Div. 2)A~D

Educational Codeforces Round 131 (Rated for Div. 2)A~D

b看错题草,dwa了9发才过巨草,c为了过快点写的很丑

Problem - A - Codeforces

问题解析

直接算这四个格子的和是多少,为0那就一次也不用,小于等于3只要一次就可以,等于4则是两次

AC代码

#include<iostream>
using namespace std;
#include<vector>
#include<algorithm>
#include<math.h>
#include<set>
#include<numeric>
#include<string>
#include<string.h>
#include<iterator>
#include<map>
#include<unordered_map>
#include<stack>
#include<list>
#include<queue>
#include<iomanip>

#define endl '\n'
#define int ll
typedef long long ll;
typedef unsigned long long ull;
typedef pair<ll, ll>PII;
const int N = 1e6 + 50, MOD = 1e9 + 7;

void solve()
{
    int a, b, c, d;
    cin >> a >> b >> c >> d;
    if (a + b + c + d == 0)cout << 0 << endl;
    else if (a + b + c + d <= 3)cout << 1 << endl;
    else cout << 2 << endl;
}

signed main()
{
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.tie(nullptr);
    int t;
    cin >> t;
    while (t--)
        solve();
    return 0;
}

Problem - B - Codeforces

问题解析

题目这里说的是让你选一个d,让a[i]*d==a[i+1]的结果尽量多,那就d取尽可能小的,即2,然后排列尽量排成a[i+1]=a[i] *2的样子即可。

AC代码

#include<iostream>
using namespace std;
#include<vector>
#include<algorithm>
#include<math.h>
#include<set>
#include<numeric>
#include<string>
#include<string.h>
#include<iterator>
#include<map>
#include<unordered_map>
#include<stack>
#include<list>
#include<queue>
#include<iomanip>

#define endl '\n'
#define int ll
typedef long long ll;
typedef unsigned long long ull;
typedef pair<ll, ll>PII;
const int N = 1e6 + 50, MOD = 1e9 + 7;

void solve()
{
    int n;
    cin >> n;
    vector<int>v(n + 1);
    cout << 2 << endl;
    for (int i = 1; i <= n; i ++)
    {
        for (int j = i; j <= n; j *= 2)
        {
            if (v[j] == 0)
            {
                cout << j << " ";
                v[j] = 1;
            }
        }
    }
    cout << endl;
}

signed main()
{
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.tie(nullptr);
    int t;
    cin >> t;
    while (t--)
        solve();
    return 0;
}

Problem - C - Codeforces

问题解析

贪心+二分答案。我们可以二分枚举需要的最少时间,上界最大是所有任务都是不擅长的人去做:2*m,下届是每个人正好都有一个擅长的任务:1。

check:我们可以先记录一下每个人有多少个要做的擅长任务,如果这个任务数大于了时间,说明这个人没法做完所有他擅长的工作,那么这个工作就要给比较空闲的人去做(即擅长任务少的人)。所以我先把所有人擅长的任务数升序排序,这样就可以让擅长任务少的人去做多余的工作。如果所有人的工作时间都无法在增长,但还有任务没做完,那说明我们的时间少了,反之时间充足。

AC代码

#include<iostream>
using namespace std;
#include<vector>
#include<algorithm>
#include<math.h>
#include<set>
#include<numeric>
#include<string>
#include<string.h>
#include<iterator>
#include<map>
#include<unordered_map>
#include<stack>
#include<list>
#include<queue>
#include<iomanip>

#define endl '\n'
#define int ll
typedef long long ll;
typedef unsigned long long ull;
typedef pair<ll, ll>PII;
const int N = 1e6 + 50, MOD = 1e9 + 7;
int f[N], n, m;
set<PII>st;
bool check(int mid)
{
	//times[i]表示第i个员工已经工作了times[i]小时
	//ans表示第i个员工做了ans[i]个不擅长的工作
    vector<int>times(n + 1),ans(n+1);
    auto t = st.begin();
    for (int i = 0; i < m; i++)
    {
        //擅长的任务数小于我们二分的时间就让擅长的人做
        if (times[f[i]] < mid)times[f[i]]++,ans[f[i]]++;
        else
        {
        	//t.second是一个员工的编号,first是他擅长任务的数量
        	//(*t).first-ans[(*t).second]就得到这个员工还要做多少个擅长的任务
        	//下面这一串式子表示:这个员工已经工作过的时间+还要做擅长的任务数+完成这个多余任务(2小时)所要的时间是否小于mid
            if (times[(*t).second]+(*t).first-ans[(*t).second] + 2 <= mid)
            {
            	//小于就让这个人做
                times[(*t).second] += 2;
            }
            else
            {
            	//做不了我们就去找下一个能做的
                while (t!=st.end()&&times[(*t).second] + (*t).first - ans[(*t).second] + 2 > mid)t++;
                //所有人都做不了这个任务,返回false
                if (t == st.end())return false;
                //找到能做的就让他做
                times[(*t).second] += 2;
            }
        }
    }
    return true;
}

void solve()
{
    st.clear();
    cin >> n >> m;
    vector<int>v(n + 1);
    
    for (int i = 0; i < m; i++)
    {
        cin >> f[i];
        //v记录每个人有多少个擅长的任务
        v[f[i]]++;
    }
    for (int i = 1; i <= n; i++)
    	//通过set的自动排序,把擅长任务数少的人放在前面
        st.insert({ v[i],i });

    int l = 1, r = m * 2;
    while (l < r)
    {
        int mid = (l + r) / 2;
        if (check(mid))r = mid;
        else l = mid + 1;
    }
    cout << l << endl;
}

signed main()
{
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.tie(nullptr);
    int t;
    cin >> t;
    while (t--)
        solve();
    return 0;
}

Problem - D - Codeforces

问题解析

先按照b[i]的值,来算得第i个位置能取的数的范围:i / (b[i]+1)+1到i / b[i]。如果b[i]为0,那么只要大于i的数都可以,如果是b[i]==i,那么这个位置就只能是1。

然后我们按照每个位置的取值范围来排序,我们尽量把右区间小的放在前面,然后每次取值的时候,都取一个最小的且还没被拿过的数。

但是直接这么写我t了,想了想原因应该是在区间l~r上找最小的且还没被拿过的数这一步骤出了问题。假设区间是[1,1000],但其实前面999个位置都已经被拿过了,但我们还是从1开始傻傻的找,很蠢。

所以我们可以用一个变量ans优化一下。ans表示所有数中还没被取走的最小的数,这样当左区间小于ans时,我们直接从ans开始找就行。

AC代码

#include<iostream>
using namespace std;
#include<vector>
#include<algorithm>
#include<math.h>
#include<set>
#include<numeric>
#include<string>
#include<string.h>
#include<iterator>
#include<map>
#include<unordered_map>
#include<stack>
#include<list>
#include<queue>
#include<iomanip>

#define endl '\n'
#define int ll
typedef long long ll;
typedef unsigned long long ull;
typedef pair<ll, ll>PII;
const int N = 1e6 + 50, MOD = 1e9 + 7;
int f[N];
vector<vector<int>>st;

bool cmp(vector<int>a, vector<int>b)
{
    if(a[2]!=b[2])
        return a[2] < b[2];
    return a[1] < b[1];
}

void solve()
{
    st.clear();
    int n;
    cin >> n;
    vector<int>v(n + 1), res(n + 1);
    for (int i = 1; i <= n; i++)
    {
        cin >> f[i];
        int l, r;
        if (f[i] == i)
        {
            res[i] = 1;
            v[1] = 1;
        }
        if (f[i] == 0)
        {
            l = i+1, r = n;
        }
        else
        {
            l = i / (f[i] + 1) + 1, r = i / f[i];
        }
        vector<int>ans{ i,l,r };
        st.push_back(ans);
    }
    sort(st.begin(), st.end(), cmp);
    int pos = 1;
    for (auto i : st)
    {
        while (v[pos])pos++;
        int x = i[0], l = i[1], r = i[2];
        for (int j = max(pos,l); j <= r; j++)
        {
            if (v[j] == 0)
            {
                v[j] = 1;
                res[x] = j;
                break;
            }
        }
    }
    for (int i = 1; i <= n; i++)
    {
        cout << res[i] << " ";
    }
    cout << endl;
}

signed main()
{
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.tie(nullptr);
    int t;
    cin >> t;
    while (t--)
        solve();
    return 0;
}
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值