zoukankan      html  css  js  c++  java
  • 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;
        }
    }
    
  • 相关阅读:
    jquery 序列化form表单
    nginx for windows 安装
    nodejs idea 创建项目 (一)
    spring 配置 shiro rememberMe
    idea 2018 解决 双击shift 弹出 search everywhere 搜索框的方法
    redis 在windows 集群
    spring IOC控制反转和DI依赖注入
    redis 的安装
    shiro 通过jdbc连接数据库
    handlebars的用法
  • 原文地址:https://www.cnblogs.com/darker-wxl/p/15087120.html
Copyright © 2011-2022 走看看