2023多校训练+补题记录

牛客第一场

好久没搞算法了,手好生(

D

签到,队友写的(

J

不难发现一次输输输赢的过程可以赢一块钱

问题就转化成了在**m**轮里,是否能每次都在不输完本金的情况下赢一把

显然这个概率是$1-(\frac{1}{2})^t$,$t$表示当前$t$轮输掉本金

$t$显然是从$log n$取到$log (m + n)$

枚举一下$t$,直接暴力乘即可

一开始把题读反了,感觉那个式子还比较有趣(

#include <bits/stdc++.h>
#define ll long long
using namespace std;
ll N,M;
const ll MOD = 998244353;
ll inv2;
ll Pow(ll x,ll y){
    ll ans = 1;
    for (;y; y >>=1){
        if(y&1) ans = ans * x % MOD;
        x = x * x % MOD; 
    }
    return ans%MOD;
}
ll pr[55];
int main(){
    inv2 = Pow(2,MOD-2);
    cin >> N >> M;
    ll x = 1;
    for (int i = 1 ; i <= 32 ; i ++){
        pr[i] = pr[i-1] + x;
        x *= 2;
    }
    ll P = 1,L=0,R=0;
    for (int i = 1 ; i <= 31 ; i ++){
        ll Sum = 0;
        Sum = (1-Pow(inv2,i)+MOD)%MOD;
        ll L = pr[i] - N,R = min(pr[i+1]-N,M);
        if (N > pr[i] && N>pr[i+1]) continue;
        if (N > pr[i]) L = 0;
        if (pr[i] > N+M) break;
        P = P*Pow(Sum,R-L)%MOD;
    }
    cout << P << endl;
    return 0;
}

K

考虑先按bfs序把原图变成一颗树

然后会发现如果有一条边,除了树边以外还有别的边与之相连的话,那么那些边随便怎么加点都不影响这个点

所以全部加满

那么考虑什么时候在树边上加点

只有叶子节点且它没有非树边的时候。

因为如果不是这样的话,把这个点加上必然会导致更深处的点被挤,最好的情况只有一个换一个,所以不会更优。

#include <bits/stdc++.h>
#define ll long long
#define int long long
using namespace std;
const int mx = 2e5+10;
queue<int> Bfs;
int N,M,K;
vector<int> G[mx];
int ans,dis[mx],pa[mx],Leaf[mx];
signed main(){
    cin >> N >> M >> K;
    for (int i = 1 ; i <= M ; i ++){
        int u,v;
        cin >> u >> v;
        G[u].push_back(v);
        G[v].push_back(u); 
    }
    for (int i = 1 ; i <= N ; i ++)
        dis[i] = -1;
    Bfs.push(1); 
    dis[1] = 0;
    while (!Bfs.empty()){
        int u = Bfs.front();
        Bfs.pop();
        for (auto v : G[u]){
            if (dis[v] != -1) continue;
            Bfs.push(v);
            dis[v] = dis[u] + 1;
            pa[v] = u;
            Leaf[u] = true;
        }
    }
    for (int i = 2 ; i <= N ; i ++){
        int u = i;
        int cnt = 0;
        if (dis[u] > K || dis[u] == -1) continue;
        for (auto v : G[i]){
            if (pa[v] == u || pa[u] == v) continue;
            cnt++;
        }
        if (!Leaf[u]){
            if (cnt == 0) cnt = 1;
        }
        ans += cnt * (K-dis[u]) + 1; 
    }
    cout << ans + 1;
    return 0;
}

H

没有脑子.jpg

考虑交换产生的$\delta$

$|a_i - b_j| + |b_i - a_j| - |a_i - b_i|-|a_j - b_j|$

需要最小化这个东西。设$w_i$ = $a_i - b_i$

分四种情况讨论,下面具体描述其中一种

不妨假设$a_i > b_j$且$b_i > a_j$

于是展开式子就变成最小化$a_i - b_j +b_i - a_j - w_i - w_j$

$a_i + b_i - w_i +( - a_j - b_j - w_j)$

枚举$i$,就是最小化后面那项

条件是$a_i > b_j$ 且 $b_i > a_j$

把$(b_i,a_i)$看成二维平面上的点,这个问题也就变成了一个标准的二维数点问题。抓个数据结构维护即可。

剩下三种情况类似地讨论即可。

然后就被卡了,现在还没过去,噔噔咚(

#include <bits/stdc++.h>
using namespace std;
const int mx = 1e6;
#define ll long long
ll inf = 0x3f3f3f3f3f3f;
vector<int> num; 
vector<int>  Add[mx+5],Q[mx+5];
int a[mx+10],b[mx+10];
int xx[mx+10],yy[mx+10];
int x[mx+10];
ll Tree1[2*mx+10];
void Clear(){
    memset(Tree1,inf,sizeof(Tree1));
}
int Lowbit(int x){
    return (x&(-x));
}
void Add1(int pos, ll nd){
    for (int i = pos ; i<= mx ; i +=Lowbit(i)){
        Tree1[i] = min(Tree1[i],nd);
    }
}
ll Get1(int x){
    ll ans = inf;
    for (int i = x ; i ; i-= Lowbit(i))
        ans = min(ans,Tree1[i]);
    return ans;
}
signed main(){
    ll ans = 0; 
    int N;
    cin >> N;
    for (int i = 1 ; i <= N ; i ++){
        cin >> a[i];
        num.push_back(a[i]);
    }
    for (int i = 1 ; i <= N ; i ++){
        cin >> b[i];
        num.push_back(b[i]);
        x[i] = abs(a[i] - b[i]);
        ans += x[i];
    }
    num.push_back(-(1e9 - 100));
    sort(num.begin(),num.end());
    num.resize(unique(num.begin(),num.end())-num.begin());
    int sz = num.size() - 1;
    for (int i = 1 ; i <= N ; i ++){
        xx[i] = lower_bound(num.begin(),num.end(),a[i]) - num.begin();
        yy[i] = lower_bound(num.begin(),num.end(),b[i]) - num.begin();
        Add[xx[i]].push_back(i);
        Q[yy[i]].push_back(i);
    }
    Clear();
    ll mn = inf;
    for (int i  = 1 ; i <= sz ; i ++){
        for (auto v : Add[i]){
            Add1(yy[v],-a[v]-b[v]-x[v]);
        }
        for (auto t : Q[i]){
            mn = min(mn,a[t] + b[t] + Get1(xx[t]) - x[t]);
        }
    }
    Clear();
    for (int i  = sz ; i >= 1 ; i --){
        for (auto v : Add[i]){
            Add1(yy[v],a[v]-b[v]-x[v]);
        }
        for (auto t : Q[i]){
            mn = min(mn,a[t] - b[t] + Get1(xx[t]) - x[t]);
        }
    }
    Clear();
    for (int i = 1 ; i <= N ; i ++)
        xx[i] = sz-xx[i] + 1;
    for (int i = 1 ; i <= N ; i ++)
        yy[i] = sz-yy[i] + 1;
    for (int i  = 1 ; i <= sz ; i ++){
        for (auto v : Add[i]){
            Add1(yy[v],-a[v]+b[v]-x[v]);
        }
        for (auto t : Q[i]){
            mn = min(mn,-a[t] + b[t] + Get1(xx[t]) - x[t]);
        }
    }
    Clear();
    for (int i  = sz ; i>= 1 ; i --){
        for (auto v : Add[i]){
            Add1(yy[v],a[v]+b[v]-x[v]);
        }
        for (auto t : Q[i]){
            mn = min(mn,-a[t] - b[t] + Get1(xx[t]) - x[t]);
        }
    }
    cout << ans + mn;
    return 0;
}

 

posted @ 2023-07-18 02:27  si_nian  阅读(25)  评论(0)    收藏  举报