Codeforces Round #835 (Div. 4)

A:三个数找中间大

void solve() {
    vector<int> a(3);
    rep(i, 0, 3)    cin >> a[i];
    sort(all(a));
    cout << a[1] << endl;
}

B:问你字符串中最大的字母对应编号

void solve() {
    int n; cin >> n;
    string s; cin >> s;
    char c = 'a';
    for (auto x : s) c = max(c, x);
    cout << c - 'a' + 1 << endl;
}

C:问你每个数与最大值的差, 最大值则与第二大的特判

void solve() {
    int n; cin >> n;
    int mx1 = -1e8, mx2 = -1e8;
    for (int i = 1; i <= n; i ++ ) {
        cin >> a[i];
        if(a[i] > mx1)  mx2 = mx1, mx1 = a[i];
        else if(a[i] > mx2) mx2 = a[i];
    }
    for (int i = 1; i <= n; i ++ ) {
        if(a[i] != mx1) cout << a[i] - mx1 << ' ';
        else cout << mx1 - mx2 << ' ';
    }
    cout << endl;
}

D:问你当前这个数组是不是有谷

void solve() {
    int n; cin >> n;
    repn(i, 1, n) cin >> a[i];
    bool fg = false;
    for (int i = 2; i <= n; i ++ ) {
        if(a[i] == a[i - 1])    continue;
        if(fg) {
            if(a[i] < a[i - 1]) {cout << "NO" << endl; return;}
        }
        if(a[i] > a[i - 1]) fg = true;
    }
    cout << "YES" << endl;
}

E:给你一个01串,你最多可以修改一个位置,将0->1, 1->0,问你最大的逆序对数量。

思路:先处理出原始的逆序对数量。然后分分别枚举每一个位置

1->0:ans减去后缀0的数量,加上前缀1的数量

0->1:ans加上后缀0的数量,减去前缀1的数量。 

 

void solve() {
    int n; cin >> n;
    for (int i = 0; i <= n + 20; i ++ ) pre1[i] = pre0[i] = end0[i] = end1[i] = 0;
    map<int, int> mp;
    ll ans = 0;
    for (int i = 1; i <= n; i ++ ) {
        cin >> a[i];
        mp[a[i]] ++;
        if(a[i] == 0)   ans += mp[1];
    }


    if(a[1] == 0)   pre0[1] = 1;
    else    pre1[1] = 1;
    for (int i = 2; i <= n; i ++ ) {
        pre0[i] = pre0[i - 1] + (a[i] == 0);
        pre1[i] = pre1[i - 1] + (a[i] == 1);
    }


    if(a[n] == 0)   end0[n] = 1;
    else    end1[n] = 1;
    for (int i = n - 1; i >= 0; i -- ) {
        end0[i] = end0[i + 1] + (a[i] == 0);
        end1[i] = end1[i + 1] + (a[i] == 1);
    }
    ll tmp = ans;
    for (int i = 1; i <= n; i ++ ) {
        if(a[i] == 1) {
            ans = max(ans, tmp - end0[i + 1] + pre1[i - 1]);
        }
        else ans = max(ans, tmp + end0[i + 1] - pre1[i]);
        //cout << ans << endl;
    }
    cout << ans << endl;

}

F:你有n个工作,每个工作对应ai的收益。你还有一个c和一个d,d是deadline。现在,完成了一个工作会有一个约束,即k天内无法再次做这个工作。现在问你d天内,我们是否可以最大化k,使得收益达到c。

思路:很明显的二分答案。我们可以二分这个答案k。贪心的考虑,我们每次肯定都是先做收益ai最大的工作。所以排个序,取模随便搞一搞就行了。注意一下define int long long

void solve() {
    cin >> n >> c >> d;
    for (int i = 1;i <= n; i++ ) cin >> a[i];
    int sum = 0, mx = 0;
    for (int i = 1; i <= n; i++ ) sum += a[i], mx = max(mx, a[i]);
    if(mx * d < c) {cout << "Impossible" << endl; return;}
    sort(a + 1, a + n + 1);
    int l = 0, r = INF;
    
    auto check = [&](int mid) {
        int res = 0;
        for (int i = n; i >= max(n - mid, 1ll); i --) res += a[i];
        int sum = 0;
        for (int i = n, j = d % (mid + 1); j >= 1 && i >= max(n - mid, 1ll); i --, j -- )   sum += a[i];

        return d / (mid + 1) * res + sum >= c;
    };
    while(l < r) {
        int mid = l + r + 1 >> 1;
        if(check(mid))  l = mid;
        else    r = mid - 1;
    }    
    if(r < INF) cout << r << endl;
    else cout << "Infinity" << endl;
}

 G:有一棵树,每条树边有一个权值w,问你从a走到b,是否能使得边的权值异或是0,但是中间你可以随便跳一次。也是在路上随便位移到另外一个点。

思路:从a开始不到b跑一边前缀异或值,放入set或者map。然后从b再出发随便跑一遍,记录异或值。如果异或值已经出现了,说明我们直接瞬移到这个点然后走回去就是0了。

vector<array<int, 2>> e[N];
int ans;
bool fg;
map<int, int> mp;

void solve() {
    cin >> n >> a >> b;
    mp.clear();
    for (int i = 0; i <= n + 10; i ++ ) e[i].clear();
    for (int i = 1;  i < n; i ++ ) {
        int a, b, c; cin >> a >> b >> c;
        e[a].pb({b, c});
        e[b].pb({a, c});
    }
    auto dfs = [&](auto&& self, int u, int fa, int cur) -> void {
        mp[cur] = 1;
        for (auto [to, v]: e[u]) {
            if(to == fa)    continue;
            if(to == b) continue;
            self(self, to, u, cur ^ v);
        }
    };

    auto dfs2 = [&](auto&& self, int u, int fa, int cur) -> void {
        for (auto [to, v] : e[u]) {
            if(to == fa)    continue;
            self(self, to, u, cur ^ v);
            if(fg)  return ;
            if(mp[cur ^ v]) {
                fg = true;
                cout << "YES" << endl;
            }
        }
    };

    dfs(dfs, a, 0, 0);
    fg = false;
    dfs2(dfs2, b, 0, 0);
    if(!fg) {cout << "NO" << endl; return;};

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值