• 2021牛客暑期多校训练营5


    2021牛客暑期多校训练营5

    B: Boxes

    • 题意

    给你n个盒子,每个盒子只有黑白两种情况,而且支付C元就可以知道未开过的盒子中黑盒的个数,问你最少知道每个盒子中球颜色的期望

    • 思路

    C(n,i) / (2 ^ n) 拿i个的概率

    1. 不问的情况 (sum w_i)
    2. (w_i)升序排序,C+ (sum w_i(1 - 1/(2 ^ {n - i}))) 求后面有i个全是同色的情况

    实在不行可以这样理解, 首先 2 / 16是不用算的, 那么 7 / 8的都要算第一个,并在之后判断是否可行, 那么1个和n-1个盒子不一样的情况,只有2中之后 16 - 2 - 2 / 16 = 3 / 4同上, 之后每种情况2中,那么 (w_1)的贡献就是 7 / 8,(w_2)的贡献是 3 / 4以此类推即可
    本题是队友过的,我太菜,呜呜呜
    code :

    double w[N];
    
    void solve(){
        int n;
        db C;
        cin >> n >> C;
        db sum = 0;
        fep(i,1,n) cin >> w[i], sum += w[i];
        db ans = C;
        sort(w + 1,w + 1 + n);
        for(int i = 1;i <= n;i ++) {
            ans += w[i] * (1 - 1.0 / (pow(2.0, n - i)));
        }
        ans = min(ans, sum);
        printf("%.6f
    ", ans);
    }
    

    D: Double Strings

    • 题意

    好的方案的构成是“一段相同的前缀+一个不同字符(a比b小)+长度相同的任意后缀”,求一共多少个好的方案

    • 思路

    dp求最长公共子序列,组合数学求后面的即可,其实读懂了题就是简单(sb)题

    code :

    typedef long long LL;
    const int N = 5010, MOD = 1e9+7;
    ll fact[N * 2], infact[N * 2];
    
    void init() {
    	fact[0] = infact[0] = 1;
        for (int i = 1 ; i < N * 2; ++i) {
            fact[i] = fact[i - 1] * i % MOD;
            infact[i] = infact[i - 1] * pow_mod(i, MOD - 2) % MOD;
        }
    }
    
    ll C(ll a,ll b) {
    	if(a<0||b<0||a<b) return 0;
    	return 1LL * fact[a] * infact[a - b] % MOD * infact[b] % MOD;
    }
    
    char a[N], b[N];
    ll f[N][N];
    
    void solve(){
        cin >> (a + 1) >> (b + 1);
        ll lena = strlen(a + 1), lenb = strlen(b + 1);
        // 最长公共子序列
        for(int i = 1;i <= lena;i ++) {
            for(int j = 1;j <= lenb;j ++) {
                if(a[i] == b[j]) f[i][j] = (f[i - 1][j] + f[i][j - 1] + 1) % mod;
                else f[i][j] = (f[i - 1][j] + f[i][j - 1] - f[i - 1][j - 1]) % mod;
            }
        }
        ll ans = 0;
        for(int i = 1;i <= lena;i ++) {
            for(int j = 1;j <= lenb;j ++) {
                if(a[i] < b[j]) {
                    // 最长前缀+当前+任意后缀
                    ans = (ans + 1LL * (f[i - 1][j - 1] + 1) % mod * C(lena - i + lenb - j, min(lena - i, lenb - j)) % mod + mod) % mod;
                }
            }
        }
        cout << ans << endl;
    }
    
    

    H: Holding Two

    • 题意

    构造一个n行m列的数组,每个数字由0和1组成,每行|竖|斜着连着三个数字是一样的都不行,让你构造

    • 思路

    我的构造方法 :
    01010101010101
    01010101010101
    10101010101010
    10101010101010
    01010101010101
    这样交替下去

    code :

    int main() {
        int n,m;
        cin >> n >> m;
        int cnt = 0;
        for(int i = 1;i <= n;i ++) {
            cnt ++;
            for(int j = 1;j <= m;j ++) {
                if(cnt != 3 && cnt != 4) {
                    if(j & 1) {
                        cout << "0";
                    }else {
                        cout << "1";
                    }
                }else {
                    if(j & 1) {
                        cout << "1";
                    }else {
                        cout << "0";
                    }
                }
            }
            if(cnt == 4) cnt = 0;
            cout << endl;
        }
    }
    

    J: Jewels

    • 题意

    有n个宝石,三维平面,你位于(0,0,0), 抓一个宝石的消耗为此宝石当前与你的距离的平方(x * x + y * y + z * z ), 你每秒只能抓一个宝石,其他宝石会以(v_i)的速度往下掉

    • 思路

    费用流建图,二分图,左边时刻,右边宝石,跑一遍ek,即可,牛客这题卡acwing的费用流模板,调死我了,其实多加个优先队列去优化即可

    code :

    
    const int N = 610, M = N * N;
    const int INF = 1e9;
    int n,m,S,T;
    int h[N],e[M],f[M],ne[M],idx;
    int incf[N],pre[N];
    bool st[N];
    ll d[N],w[M],ans = 0;
    struct node {
        ll x,y,z,v;
    }a[N];
    
    inline void add(int a,int b,int c,ll d){
        e[idx] = b,ne[idx] = h[a],f[idx] = c,w[idx] = d,h[a] = idx ++;
        e[idx] = a,ne[idx] = h[b],f[idx] = 0,w[idx] = -d,h[b] = idx ++;
    }
    
    inline bool spfa(){
        for(int i= 0;i < 2 * n + 3;i ++ ) {
            d[i] = 2e18;
            incf[i] = 0;
        }
        priority_queue<pair<ll,int> >q;
        q.push(make_pair(0,S));
        d[S] = 0,incf[S] = INF;
        while(!q.empty()){
            int t = q.top().second;
            q.pop();
            st[t] = false;
            for(int i = h[t];~i;i = ne[i]){
                int j = e[i];
                if(f[i] && d[j] > d[t] + w[i]){
                    d[j] = d[t] + w[i];
                    pre[j] = i;
                    incf[j] = min(f[i],incf[t]);
                    if(!st[j]){
                        st[j] = 1;
                        q.push(make_pair(-1LL * d[j],j));
                    }
                }
            }
        }
        return incf[T] > 0;
    }
    
    ll EK(){
        ll cost = 0;
        while(spfa()){
            ll t = incf[T];
            cost += t * d[T];
            for(int i = T;i != S;i = e[pre[i] ^ 1]){
                f[pre[i]] -= t;
                f[pre[i] ^ 1] += t;
            }
        }
        ans = ans + cost;
        return cost;
    }
    
    void solve(){
        scanf("%d", &n);
        for(int i = 1;i <= n;i ++) {
            scanf("%lld%lld%lld%lld", &a[i].x, &a[i].y, &a[i].z, &a[i].v);
            ans += 1LL * a[i].x * a[i].x + a[i].y * a[i].y;
        }
        memset(h,-1,sizeof h);
        S = 2 * n + 2,T = 2 * n + 1;
        for(int i = 0;i < n;i ++) {
            add(S,i,1,0);
        }
        for(int i = n + 1;i <= 2 * n;i ++) {
            add(i,T,1,0);
        }
        for(int i = 0;i < n;i ++) {
            for(int j = n + 1;j <= 2 * n;j ++) {
                add(i,j,1,(a[j - n].z + i * a[j - n].v) * (a[j - n].z + i * a[j - n].v));
            }
        }
        EK();
        printf("%lld
    ", ans);
    }
    

    K: King of Range

    • 题意

    给你一个长度为n的序列,让你找到有多少对(l,r) 另 (max(a_l,a_{l+1},···,a_r)) - (min(a_l,a_{l+1},···,a_r))严格大于k,并且给出m次k

    • 思路

    单调队列或单调栈或双端队列(队友写过的) 去维护当前最大值最小值的下标,并且维护不能取的数量,每次用n * (n + 1) / 2减去即可

    code :

    
    #define int long long
    int n,m;
    int a[N];
    
    int qa[N],qi[N];
    
    void solve(){
        cin >> n >> m;
        fep(i,1,n) cin >> a[i];
        while(m --) {
            int ans = (n + 1) * n / 2;
            int k;
            int h1 = 0,t1 = -1, h2 = 0, t2 = -1;
            cin >> k;
            int l = 1;
            for(int i = 1;i <= n;i ++) {
                // 记录最大值
                while(h1 <= t1 && a[qa[t1]] < a[i]) t1 --;
                qa[++ t1] = i;
                // 记录最小值
                while(h2 <= t2 && a[qi[t2]] > a[i]) t2 --;
                qi[++ t2] = i;
                while(h1 <= t1 && h2 <= t2 && a[qa[h1]] - a[qi[h2]] > k) {
                    // 删除贡献
                    if(qa[h1] == l) h1 ++;
                    if(qi[h2] == l) h2 ++;
                    l ++;
                }
                ans -= (i - l + 1);
            }
            cout << ans << endl;
        }
    }
    
  • 相关阅读:
    C#中泛型学习笔记
    ASP.NET C#各种数据库连接字符串大全——SQLServer、Oracle、Access
    单点登录SSO
    Package Manager Console 向VS2010安装 EntityFramework
    JavasSript中类的实现(1)
    Java线程实现提供者消费者模式
    MySQL插入语句解决唯一键约束
    【BZOJ4000】【LOJ2104】【TJOI2015】棋盘 (状压dp + 矩阵快速幂)
    【AGC005F】Many Easy Problems (NTT)
    【Luogu4630】【APIO2018】 Duathlon 铁人两项 (圆方树)
  • 原文地址:https://www.cnblogs.com/darker-wxl/p/15087120.html
Copyright © 2020-2023  润新知