zoukankan      html  css  js  c++  java
  • HGOI 20190714

    最后一题各种坑爹玩野,被坑到80
    还好没有像某奕一样被坑到40嘿嘿
    整体海星,加油

    T1 淘汰赛制(elimination)

    很明显是概率 (dp)(其实可以模拟,而且很多人过了)

    (dp[i][j]) 表示第 (i)(j) 还存活的概率
    转移:$dp[i][j] = dp[i - 1][j] * sumlimits_{k 是它可能遇到的} f[i - 1][k] * a[j][k] $

    (k) 是一个区间, 但是必须满足经过 (i) 轮之后与 (j) 成为对手

    这样的 (k) 满足一个一个性质,即 (id(k)=id(j)±1, id(j) = (j-1)/2^{(i-1)}+1)

    (±1) 根据 (id(j)) 的奇偶而定

    然后在 (dp[n][i])(max) 即可

    #include<bits/stdc++.h>
    #define rep(i, a, b) for (int i = a; i <= b; i++) 
    using namespace std;
    
    const int N = 1 << 11 ;
    
    int k, n, m, stp, ans ;
    int a[N][N] ;
    double f[N][N], Max ;
    // f[i][j] 表到第 i 轮 j 获胜的概率
    // f[i][j] = f[i - 1][j] * sum(f[i - 1][k] * a[j][k])
    
    int id(int x) {
    	return (x - 1) / stp + 1 ;
    }
    
    signed main() {
    	freopen("elimination.in", "r", stdin) ;
    	freopen("elimination.out", "w", stdout) ;
    	scanf("%d", &n) ;
    	rep(i, 1, (1 << n))
    	rep(j, 1, (1 << n))
    	scanf("%d", &a[i][j]) ;
    	rep(j, 1, (1 << n)) f[0][j] = 1 ;
    	stp = 1 ;
    	rep(i, 1, n) {
    		rep(j, 1, (1 << n)) {
    		   	double s = 0 ;
    	 	    f[i][j] = f[i - 1][j] ; 
    	 	    int curid = id(j), beat ;
    	 	    if (curid & 1) beat = curid + 1 ; 
    			else beat = curid - 1 ;
    			rep(k, 1, (1 << n)) if (id(k) == beat) s += f[i - 1][k] * a[j][k] / 100 ;
    	        f[i][j] *= s ; 
            }
            stp *= 2 ;
        }
        rep(i, 1, (1 << n))
        if (f[n][i] > Max) {
         	Max = f[n][i] ; ans = i;
        }
        printf("%d
    ", ans) ;
        return 0 ;
    }
    

    T2 种树(trees)

    这题相对简单

    首先对要求按 (l) 从小到大排序

    然后考虑每个要求

    对于一个操作,我们要将其完成,且其能够尽可能多的完成后面的要求

    因此我们从后往前放树

    时间复杂度 (O(wh))

    #include <bits/stdc++.h>
    using namespace std;
    
    #define rep(i, a, b) for (int i = a; i <= b; i++)
    #define per(i, a, b) for (int i = a; i >= b; i--)
    #define siz(a) (int)a.size()
    #define pb push_back
    #define mp make_pair
    #define ll long long
    #define fi first
    #define se second
    
    const int N = 100010 ;
    
    int n, m, ans ;
    int v[N] ;
    
    struct node {
    	int l, r, t ;
    	bool operator < (const node &rhs) const {
    		return r == rhs.r ? l < rhs.l : r < rhs.r ;
    	}
    } a[N] ;
    
    signed main() {
    	freopen("trees.in", "r", stdin) ;
    	freopen("trees.out", "w", stdout) ;
    	scanf("%d%d", &n, &m) ;
    	rep(i, 1, m) scanf("%d%d%d", &a[i].l, &a[i].r, &a[i].t) ;
    	sort(a + 1, a + m + 1) ;
    //	rep(i, 1, m) printf("%d %d %d
    ", a[i].l, a[i].r, a[i].t) ;
    	rep(i, 1, m) 
    	if (a[i].t > 0) {
    		int pos = a[i].r ;
    		ans += a[i].t ;
    		rep(j, 1, a[i].t) {
    			while (v[pos]) pos-- ;
    			v[pos] = 1 ;
    			rep(k, i + 1, m) if (a[k].l <= pos && pos <= a[k].r) a[k].t-- ;
    		}
    	}
    	printf("%d
    ", ans) ;
    	return 0 ;
    }
    
    

    T3 软件开发(software)

    一眼就二分

    二分答案,我们只需要考虑能否实现

    (f[i][j]) 表示前 (i) 个人做了 (j) 个任务 (1) 的模块后还能做的任务 (2) 的模块数

    转移方程: (f[i][j] = max(f[i][j], f[i - 1][k] + (x - (j - k) * d1[i]) / d2[i]))

    如果 (f[n][m] >= m) 答案就可以实现

    注意两个坑点:

    1. 开始要全部赋 (-∞)
    2. 二分右边界不能太大,不然 (dp) 会爆 (int)

    时间复杂度 (O(N^3))

    #include <bits/stdc++.h>
    using namespace std;
    
    #define rep(i, a, b) for (int i = a; i <= b; i++)
    #define per(i, a, b) for (int i = a; i >= b; i--)
    #define siz(a) (int)a.size()
    #define pb push_back
    #define mp make_pair
    #define ll long long
    #define fi first
    #define se second
    
    const int iinf = 0x3f3f3f3f ;
    const int N = 1010 ;
    
    int f[N][N] ; // f[i][j] 表示前i个人做了j个任务1的模块后还能做的任务2的模块数 
    
    int n, m, ans ;
    int d1[N], d2[N] ;
    
    bool check(int x) {
    	memset(f, -1, sizeof(f)) ;
    	f[0][0] = 0 ;
    //	rep(i, 1, m) f[0][i] = -iinf ;
    	rep(i, 1, n)
    	rep(j, 0, m)
    	rep(k, 0, j) 
    	if (x >= (j - k) * d1[i] && f[i - 1][k] != -1)
    	f[i][j] = max(f[i][j], f[i - 1][k] + (x - (j - k) * d1[i]) / d2[i]) ;
    //	rep(i, 1, n) {
    //		rep(j, 0, m) cout << f[i][j] << " " ;
    //		cout << endl ;
    //	}
    	return f[n][m] >= m ;
    } 
    
    signed main() {
    //	freopen("software.in", "r", stdin) ;
    //	freopen("software.out", "w", stdout) ;
    	scanf("%d%d", &n, &m) ;
    	rep(i, 1, n) scanf("%d%d", &d1[i], &d2[i]) ;
    	int l = 0, r = 20000, ans = 0 ;
    	while (l <= r) {
    		int mid = (l + r) >> 1 ;
    		if (check(mid)) ans = mid, r = mid - 1 ;
    		else l = mid + 1 ;
    	}
    //	ans = 0 ;
    //	rep(i, max(0, l - 5), min(iinf, r + 5)) 
    //	if (check(i)) {
    //		ans = i ;
    //		break ;
    //	}
    //	check(15) ;
    	printf("%d
    ", ans) ;
    
    	return 0 ;
    }
    
    
    
  • 相关阅读:
    sql 相关子查询
    sql 执行计划
    SQL表连接查询(inner join、full join、left join、right join)
    sql执行顺序
    sql 语句 嵌套子查询 执行顺序分析
    只有程序员才看得懂的情书
    Give Me an E
    hdu 1114 (背包变形)
    模版 并查集
    背包 讲解
  • 原文地址:https://www.cnblogs.com/harryhqg/p/13300096.html
Copyright © 2011-2022 走看看