20220719杭电第一场

Random

题目描述:
N个数字,随机生成[0,1]之间的数
做M次操作,1/2概率删除最大值,1/2概率删除最小值
计算期望值总和,结果对10^9+7取模

想法:
从题目上来看N个数可以看做都是0.5,每进行一次操作就可以减少0.5,所以最终答案就是(n-m)/2%(mod)
但是需要注意的是这里使用除法逆元去计算结果,否则就会出问题,比赛时就是因为这个没通过。

知识点:除法逆元

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

const ll p = 1e9 + 7;

ll fast_pow(ll a, ll b, ll p) {
    ll ans = 1;
    a %= p;
    while (b != 0) {
        if (b & 1) {
            ans = (ans * a) % p;
        }
        a = (a * a) % p;
        b >>= 1;
    }
    return ans;
}

int main() {
    int times;
    cin >> times;
    while (times--) {
        int n, m;
        cin >> n >> m;
        cout << (n - m) * fast_pow(2, p - 2, p) % p << endl;
    }
}

Alice and Bob

题目描述:
有m个写在黑板上的数字,所有这些都是介于0和n.
如果黑板上还有数字,并且没有带值的数字0在黑板上,爱丽丝可以将黑板上剩余的数字分成两组。
Bob 选择其中一组并擦除该集中的所有数字。然后将所有剩余的数字减去一。
在任何时候,如果有一个值为0在黑板上,爱丽丝获胜;否则,如果黑板上的所有数字都被擦除,则鲍勃获胜。
请确定如果爱丽丝和鲍勃都以最佳方式玩游戏,谁将赢得游戏。

想法:
如果至少有两个1,将它们分开,无论Bob做什么选择,Alice都可以获胜
如果至少有一个1,至少有两个2,可以得到至少两个1
如果至少有4个2,将它们分开,可以得到至少两个1
由此可以得到两个i+1可以等价为一个i

#include <bits/stdc++.h>

using namespace std;
typedef long long ll;


ll a[1000009];

int main() {
    int t;
    cin >> t;
    while (t--) {
        int n;
        cin >> n;
        for (int i = 0; i <= n; i++) {
            cin >> a[i];
        }
        for (int i = n; i >= 1; i--) {
            a[i - 1] += a[i] / 2;
        }
        if (a[0] >= 1) {
            cout << "Alice" << endl;
        } else {
            cout << "Bob" << endl;
        }
    }
    return 0;
}

Laser

题目描述:
在平面上有很多点,是否能够用一个“米”字使得所有的点都在这四条线上。

想法:
我们先从第一个点出发,依次枚举四个方向abcd,如果发现某个点不在枚举的方向上,例如a,那么从那个点出发枚举bcd方向,我们就可以得到与a方向的三个交点,再从这三个交点入手暴力枚举四个方向,就能得到结果

#include<iostream>

using namespace std;


const int N = 5e5 + 10;
int x[N], y[N], n;


int check1() {
    for (int i = 1; i <= n; i++) {
        if (y[i] != y[1]) {
            return i;
        }
    }
    return 0;
}

int check2() {
    for (int i = 1; i <= n; i++) {
        if (x[i] != x[1]) {
            return i;
        }
    }
    return 0;
}

int check3() {//右
    for (int i = 1; i <= n; i++) {
        if ((x[i] - x[1]) != (y[i] - y[1])) {
            return i;
        }
    }
    return 0;
}

int check4() {//左
    for (int i = 1; i <= n; i++) {
        if ((x[i] - x[1]) != (-(y[i] - y[1]))) {
            return i;
        }
    }
    return 0;
}

bool isCenter(int a, int b) {
    for (int i = 1; i <= n; i++) {
        if (x[i] == a || y[i] == b || abs(a - x[i]) == abs(b - y[i])) {
            continue;
        }
        return false;
    }
    return true;
}

bool solve() {
    cin >> n;
    for (int i = 1; i <= n; i++) {
        cin >> x[i] >> y[i];
    }
    int i;
    i = check4();
    if (i) {
        if (isCenter(x[i], -x[i] + y[1] + x[1]) || isCenter(y[1] + x[1] - y[i], y[i]) ||
            isCenter((y[1] + x[1] - y[i] + x[i]) >> 1, (-x[i] + y[1] + x[1] + y[i]) >> 1))
            return true;
    } else {
        return true;
    }
    i = check3();
    if (i) {
        if (isCenter(x[i], x[i] + y[1] - x[1]) || isCenter(y[i] - y[1] + x[1], y[i]) ||
            isCenter((y[i] - y[1] + x[1] + x[i]) >> 1, (x[i] + y[1] - x[1] + y[i]) >> 1))
            return true;
    } else {
        return true;
    }
    i = check2();
    if (i) {
        if (isCenter(x[1], y[i]) || isCenter(x[1], y[i] - x[i] + x[1]) || isCenter(x[1], y[i] + x[i] - x[1]))
            return true;
    } else {
        return true;
    }
    i = check1();//找到不与第一个点同处于水平线上的i点
    if (i) {
        if (isCenter(x[i], y[1]) || isCenter(x[i] + y[1] - y[i], y[1]) || isCenter(x[i] - y[1] + y[i], y[1]))
            return true;
    } else {
        return true;
    }
    return false;
}

int main() {
    std::ios::sync_with_stdio(false);
    cin.tie(0);
    int t;
    cin >> t;
    while (t--) {
        if (solve()) {
            cout << "YES" << endl;
        } else {
            cout << "NO" << endl;
        }

    }
}

Backpack

题目大意:
背包容量为m
有n个物品,每个物品都有volume和weight
求在背包装满的条件下最大的价值为多少

官方解释:
图片说明

个人理解:
对于那个转移方程,
如果f(i-1,j,k)=1,表示不拿i位置的值我们也可以做到前i个物品异或和为j并且体积为k,
如果f(i-1,j^v,k-w)=1,表示的是拿上i位置的值我们可以做到前i个物品异或和为j并且体积为k,
只要两种情况有一种成立就f(i,j,k)就存在,所以f(i,j,k)=f(i-1,j,k)|f(i-1,j^v,k-w)。(j^v ^v = j,k-w +w = k)
由于所有的状态都是0或者1,我们可以使用bitset进行操作。

#include<iostream>

using namespace std;

#include<bitset>


int n, m;
bitset<1025> f[1025], g[1025];


void solve() {
    for (int i = 0; i < 1024; i++) {
        f[i].reset();
        f[i].reset();
    }
    f[0][0] = 1; //异或和为0并且体积为0的情况存在
    cin >> n >> m;
    int v, w;
    for (int i = 1; i <= n; i++) {
        cin >> v >> w;
        for (int i = 0; i < 1024; i++) {
            g[i] = f[i];
            g[i] <<= v;//由于数组是从左往右开始,bitset是从右往左开始,所以左移代表着减去当前的体积。
        }
        for (int i = 0; i < 1024; i++) {
            f[i] |= g[i ^ w];
        }
    }
    int ans = -1;
    for (int i = 0; i < 1024; i++) {
        if (f[i][m]) {
            ans = i;
        }
    }
    cout << ans << endl;

}


int main() {
    int t;
    cin >> t;
    while (t--) {
        solve();
    }
}
#杭电##ACM##来新手村#
全部评论
这是笔试?4道代码题?
点赞 回复 分享
发布于 2022-07-26 20:37

相关推荐

2 收藏 评论
分享
牛客网
牛客企业服务