Educational Codeforces Round 117 A-E

本文最后更新于:2 年前

A. Distance

题意:给出 $B$ 点坐标 $bx,by$,要输出 $C$ 的坐标使得 $C$ 到原点,$C$ 到 $B$ 点的曼哈顿距离都为 $B$ 到原点的曼哈顿距离的一半。

分奇偶讨论即可

int n, m;
void solve() {
    int x, y;
    cin >> x >> y;
    int dis =(abs(x) + abs(y));
    if(dis % 2 == 0){
        if(abs(x) % 2 == 0){
            cout << x/2 << ' ' << y/2 << '\n';
        }else{
            cout << floor(x/2.0) << ' ' << ceil(y/2.0) << '\n';
        }
    }else{
        cout << "-1 -1\n";
    }
}

B. Special Permutation

题意:要构造一个 $n$ 的排列($n$ 为偶数),使得左半边最小值为 $a$,右半边最小值为 $b$

左边取 $a$ 和尽可能大的值,右边取 $b$ 和尽可能小的值,因为 $n$ 只给了100,可以 $n^2$ 暴力,省去了分类讨论的麻烦

int n, m, s[maxn];
bool vis[maxn];

void solve() {
    int a, b;
    cin >> n >> a >> b;
    for(int i=1;i<=n;i++) vis[i] = 0;
    s[1] = a; vis[a] = 1;
    for(int i=2;i<=n/2;i++){
        for(int j=n;j>=a;j--){
            if(!vis[j] && j != b){
                s[i] = j;
                vis[j] = 1;
                break;
            }
            if(j == a){
                cout << "-1\n";
                return;
            }
        }
    }
    for(int i=n/2+1;i<=n;i++){
        for(int j=b;j>=1;j--){
            if(!vis[j]){
                s[i] = j;
                vis[j] = 1;
                break;
            }
            if(j == 1){
                cout << "-1\n";
                return;
            }
        }
    }
    for(int i=1;i<n;i++) cout << s[i] << ' ';
    cout << s[n] << '\n';
}

C. Chat Ban

题意:你要依次发送 $2k-1$ 条消息,每条消息的字符个数分别为 1,2,3…k,k-1…2,1,输入达到 $x$ 个字符时就会终止,问能发出几条消息(发一半也算)

分类讨论写比较麻烦,写一个计算发送前 $x$ 条消息需要的字符的函数 $f(x)$,然后二分答案即可。

ll k, x;
ll cntk(ll s){
    if(s <= k) return s*(s+1)/2;
    else{
        ll r = (2*k-1-s+k) * (s-k) / 2;
        return k*(k+1)/2 + r;
    }
}

void solve() {
    cin >> k >> x;
    ll l = 1, r = 2*k-1;
    while(l < r){
        ll mid = (l+r) / 2;
        if(cntk(mid) >= x){
            r = mid;
        }else{
            l = mid+1;
        }
    }
    cout << l << '\n';
}

D. X-Magic Pair

题意:有两个数字 $a,b$,可以一次操作将 $a=|a-b|$ 或 $b=|a-b|$,问能否凑出 $x$($a$ 或 $b$ 等于 $x$ 都可,可以进行任意次操作)

用手模拟一下可以发现,当前为 $a,b$(假设 $a\lt b$),不论怎么操作一定会经过 $a,b-a$ 这个状态

那么可以用类似辗转相除法的办法处理,如果 $x$ 在 $a,b$ 之间且 $x\equiv b\pmod a$,则可行,否则变化为 $b%a,a$ 继续;

记得判余数为 $0$ 的情况

bool judge(ll a, ll b, ll x){
    if(a == 0 || b == 0) return 0;
    if(x == a || x == b) return 1;
    if(x > b) return false;
    if(b%a == x%a) return 1;
    return judge(b%a, a, x);
}

void solve() {
    ll a, b, x;
    string sout[2] = {"NO", "YES"};
    cin >> a >> b >> x;
    if(a > b) swap(a, b);
    cout << sout[judge(a, b, x)] << '\n';
}

E. Messages

题意:有 $n$ 个人,每个人有一个期望读到的信 $m_i$,和他将读的信数 $k_i$,每个人都会在信堆里等概率地随机抽取 $k_i$ 封信阅读(不会取走)。现在你可以选择将哪些信放进信堆,使得读到想读信的人数期望最大。

第一反应想到了二分答案,因为确定了要放信的数量后比较容易judge


考虑怎么计算:选择一共放 $m$ 封信时的最大期望

对于每个人来说,它读到想要的信的概率是 $\frac{min(k_i, m)}{m}$,我们可以对于每一封信,统计想读它的人的 $\min(k_i, m)$ 之和(记为 $tot$),那么选这封信的收益就是 $\frac{tot}{m}$ ;

将信按照 $tot$ 排序后选取前 $m$ 封就可以计算出最大期望了


然后很显然地发现,答案不具有单调性,二份答案X

输入数据保证了 $k\le20$,用手模拟了一下极端情况,大胆猜测选 $20$ 封左右信时收益达到阈值,再多选收益一定更低

然后暴力跑了 $m\le50$ 的情况,就过了!

int n;
int a[maxn], b[maxn];
bool apr[maxn];
vector<int> all;
ll tot[maxn];
double ans[maxn];
 
bool cmpf(ll x, ll y){ return x > y;}
 
double judge(int m){
    for(int i=1;i<=n;i++){
        tot[a[i]] += min(b[i], m);
    }
    sort(tot+1, tot+200000+1, cmpf);
    ll fz = 0;
    for(int i=1;i<=m;i++){
        fz += tot[i];
    }
    int i = 1;
    while(tot[i] > 0) tot[i++] = 0;
    return fz * 1.0 / m;
}
 
void solve() {
    cin >> n;
    for(int i=1;i<=n;i++){
        cin >> a[i] >> b[i];
        if(!apr[a[i]]){
            all.push_back(a[i]);
            apr[a[i]] = 1;
        }
    }
    int p = 1;
    for(int i=1;i<=min(50, n);i++){
        ans[i] = judge(i);
        if(ans[i] > ans[p]) p = i;
    }
    cout << p << '\n';
    for(int i=1;i<=n;i++) tot[a[i]] += min(b[i], p);
    vector<pair<int, int>> vp;
    for(int v:all) vp.push_back({tot[v], v});
    sort(vp.begin(), vp.end());
    bool fg = false;
    while(p--){
        if(fg) cout << ' ';
        else fg = 1;
        cout << vp.back().second;
        vp.pop_back();
    }
    cout << '\n';
}

Educational Codeforces Round 117 A-E
http://www.lxtyin.ac.cn/2021/11/22/2021-11-22-Educational Codeforces Round 117/
作者
lx_tyin
发布于
2021年11月22日
许可协议