• HGOI 20190713


    今天的题还是一如既往的良心,结果却不尽人意
    诶,菜鸡选手在线嘲讽自己

    T1 小明搬家(box)

    这个题目是比较适宜的T1

    把我这种菜鸡区分掉了

    考场以为是个小sb题,然后就没检查

    结果大数据都跪了。

    菜!

    首先处理每个人移走一个箱子的结果

    然后后面的每 (k) 个箱子的都是重复的,可以直接累加

    如果还有剩余那么就找到那个最慢的一个把箱子扛上来的人

    #include <bits/stdc++.h>
    using namespace std;
    
    #define int long long
    #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 = 500100;
    
    int n, k, m, ans ;
    int a[N], b[N] ;
    priority_queue <int, vector <int>, greater<int> > q ;
    
    int cmp(int a, int b) {
    	return a < b ;
    }
    
    signed main() {
    //	freopen("box.in", "r", stdin) ;
    //	freopen("box.out", "w", stdout) ;
    	scanf("%lld%lld%lld", &n, &k, &m) ;
    	int t = 0 ;
    	rep(i, 1, k) {
    		scanf( "%lld%lld" , &a[i] , &b[i]) ;
    		if (b[i]) a[i] = a[i] - 1 + n - 1 ;
    		else {
    			t = max(t, n - a[i]) ;
    			a[i] = 2 * (n - 1) + n - a[i] ;
    		}
    	}
    	ll ans = 0 ;
    	ans += 2 * (n - 1) * (m / k) ;
    	m %= k ;
    	if (m != 0) {
    		sort(a + 1, a + k + 1, cmp) ;
    		t = max(a[m], t) ;
    	}
    	ans += t ;
    	printf("%lld", ans) ;
    	return 0 ;
    }
    

    T2 圆圈舞蹈

    这个题目可以用O(n)的 two-pointers 做

    但是我这个菜鸡自然想到的是 (O(nlogn)) 的二分

    首先倍长一段

    然后我们找到那个以 (i) 为起点和终点的序列

    查找那个距离最大的点,二分实现

    代码里的二分看着很假,用着海星,。em

    #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 = 200010 ;
    
    int n ;
    ll ans ;
    ll a[N], sum[N] ;
    
    signed main() {
    	scanf("%d", &n) ;
    	rep(i, 1, n) scanf("%lld", &a[i]) ;
    	rep(i, 1, n) a[i + n] = a[i] ;
    	rep(i, 1, 2 * n) sum[i] = sum[i - 1] + a[i] ;
    	rep(i, 1, n) {
    		ll cur = 0 ;
    		int l = i, r = i + n ;
    		ll Min = 1e17 ;
    		while (l <= r) {
    			int mid = (l + r) >> 1 ;
    			int x = sum[mid] - sum[i], y = sum[i + n] - sum[mid] ;
    			if (abs(x - y) < Min) {
    				Min = abs(x - y) ;
    				cur = min(x, y) ;
    				ans = max(ans, cur) ;
    			}
    			if (l == mid) break ;
    			if (x < y) l = mid ;
    			else r = mid  ;
    		}
    	}
    	printf("%lld
    ", ans) ;
    	return 0 ;
    }
    
    

    T3 物流运输(trans)

    这个题目好像是某省省选题,结果就被机房大部分人切了

    蛮简单的

    (n,m) 超小,随便写

    感觉可以加强到 500,500,这样可以把状压的代码卡掉

    预处理以单一路线从 (i) 天到第 (j) 天的最短路
    (即第 (i) 天到第 (j) 天中有被封闭的路都不能走)

    考虑dp

    介绍一种 (O(n^2))的方法

    (dp[i]) 表示处理到第 (i) 天的最小花费

    考虑第i天,要么是从 (1)(i) 都是一成不变,要么中间变

    枚举最近的一次变化,然后取 (min) 即可

    转移方程见代码

    #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 = 110 ;
    
    struct Edge {
    	int t, v ;
    } ; 
    
    vector <Edge> e[N] ;
    
    int n, k, m, E, d ;
    bool ok[N][N] ;
    bool vis[N], valid[N] ;
    int dis[N] ;
    queue <int> q ;
    int cost[N][N] ;
    ll dp[N] ;
    
    int spfa(int a, int b) {
        memset(vis, 0, sizeof(vis)) ;
        memset(dis, 0x3f, sizeof(dis)) ;
        memset(valid, true, sizeof(valid)) ;
        while (!q.empty()) q.pop() ;
        rep(i, 1, m)
        rep(j, a, b)
        if (!ok[i][j])
        valid[i] = false ; q.push(1) ; 
        vis[1] = 1 ; dis[1] = 0 ;
        while (!q.empty()) {
        	int u = q.front() ; q.pop() ;
        	vis[u] = 0 ;
        	rep(i, 0, siz(e[u]) - 1) {
        		int v = e[u][i].t, val = e[u][i].v ;
        		if (!valid[v]) continue ;
        		if (dis[v] > dis[u] + val) {
        			dis[v] = dis[u] + val ;
        			if (!vis[v]) {
        				vis[v] = 1 ;
        				q.push(v) ;
    				}
    			}
    		}
    	} 
        return dis[m] ;
    }
    
    signed main() {
    	freopen("trans.in", "r", stdin) ;
    	freopen("trans.out", "w", stdout) ; 
        scanf("%d%d%d%d", &n, &m, &k, &E) ; // n 表示货物运输所需天数,m 表示码头总数,K 表示每次修改运输路线所需成本。
        rep(i, 1, E) {
        	int u, v, w ; scanf("%d%d%d", &u, &v, &w) ;
        	e[u].pb((Edge) {v, w}) ;
        	e[v].pb((Edge) {u, w}) ;
    	}
    	scanf("%d", &d) ;
    	memset(ok, true, sizeof(ok)) ;
    	rep(i, 1, d) {
    		int a, b, p ; scanf("%d%d%d", &p, &a, &b) ;
    		rep(j, a, b) ok[p][j] = false ;
    	}
    	rep(i, 1, n)
    	rep(j, 1, n)
    	cost[i][j] = spfa(i, j) ;
    	rep(i, 1, n) {
    		dp[i] = 1ll * cost[1][i] * i ; // 1~i 
    		rep(j, 1, i - 1) dp[i] = min(dp[i], dp[j] + k + 1ll * cost[j + 1][i] * (i - j)) ;  // 1~j,j+1~i 
    	}
    	printf("%lld
    ", dp[n]) ;
    	return 0 ;
    }
    /*
    5 5 10 8
    1 2 1
    1 3 3
    1 4 2
    2 3 2
    2 4 4
    3 4 1
    3 5 2
    4 5 2
    4
    2 2 3
    3 1 1
    3 3 3
    4 4 5
    */
    
  • 相关阅读:
    toggle
    Java 运算符
    Java 修饰符
    Java 变量类型
    java对象和类
    java基础笔记
    Java添加事件的几种方式(转载了codebrother的文章)
    mybatis中的#和$的区别?
    为什么java里面经常作List判断的时候,既要判断list不为null,又要判断size>0呢,岂不是多此一举吗?
    发送邮件功能 Service 层
  • 原文地址:https://www.cnblogs.com/harryhqg/p/13296375.html
Copyright © 2020-2023  润新知