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\n", 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\n", 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
*/
posted @ 2020-07-13 22:41  harryhqg  阅读(108)  评论(1编辑  收藏  举报