20230516 solution ( gas + group + drop )

T1
设 f[i][j] 代表氧气为i 氮气为j的最小重量
则有 当 i < ai && j < bi 时 f[i][j] = min(f[i][j], ci)
当 i < ai && j >= bi 时 f[i][j] = min(f[i][j], f[0][j - bi] + ci]
当 i >= ai && j < bi 时 f[i][j] = min(f[i][j], f[i - ai][0] + ci]
else f[i][j] = min(f[i - ai][j - bi] + c[i], f[i][j])

合起来就是 f[i][j] = min(f[i][j], f[max(0, i - ai)][max(0, i - bi)] + ci]
答案 f[m][n][k]

开三维数组空间约为1e7 不会MLE
时间复杂度O(mnk) 不会TLE
code :

#include <bits/stdc++.h>
using namespace std;

const int N = 1010;
int f[101][101][1010]; // O N id
int m, n;
int nowm, nown;
int k;

int main() {
//	memset(f, 0x3f, sizeof f );
	scanf("%d%d", &m, &n);
	scanf("%d", &k);
	for (int num = 1; num <= k; ++num) {
		int a, b, c;
		scanf("%d%d%d", &a, &b, &c);
		nowm += a, nown += b;
		for (int i = 0; i <= min(nowm, m); ++i) {
			for (int j = 0; j <= min(nown, n); ++j) {
				if (f[i][j][num - 1] == 0 && !(i == 0 && j == 0)) f[i][j][num] = f[max(0, i - a)][max(0, j - b)][num - 1] + c;
				else f[i][j][num] = min(f[i][j][num - 1], f[max(0, i - a)][max(0, j - b)][num - 1] + c);
			}
		}
	}
	
	printf("%d",f[m][n][k]);
	
	return 0;
}

T2
要保证每组最多只能拿一个 那么比如说我拿第i组第3个的时候就不要考虑拿了第1 2个的情况
那么这个时候当前状态还是由第i - 1组转移过来而不是由第i组第2个转移过来 这样就可以保证每组只拿一个

开二维数组空间为VT 不会MLE
时间复杂度O(NV) 不会TLE
code :

#include <bits/stdc++.h>
#define ll long long
using namespace std;

ll f[210][15];
int id[33][15], top[15]; //用vector更好
int w[33], c[33];
int v, n, t;

int main() {
	scanf("%d%d%d", &v, &n, &t);
	for (int i = 1; i <= n; ++i) {
		int zu;
		scanf("%d%d%d", &w[i], &c[i], &zu);
		id[++top[zu]][zu] = i;
	}
	
	for (int i = 1; i <= t; ++i) {
		for (int j = 1; j <= top[i]; ++j) {
			int now = id[j][i];
			for (int k = 0; k <= v; ++k) {
				if (w[now] > k) f[k][i] = max(f[k][i - 1], f[k][i]);
				else f[k][i] = max(max(f[k][i - 1], f[k][i]), f[k - w[now]][i - 1] + c[now]);
			}
		}
		if (top[i] == 0) {
			for (int k = 0; k <= v; ++k) f[k][i] = f[k][i - 1];
		}
	}
	
	printf("%lld",f[v][t]);

	return 0;
}

T3
直接模拟复杂度 O(DI) 显然能过
code :

#include <bits/stdc++.h>
#define ls (x << 1)
#define rs (x << 1 | 1)
using namespace std;

const int N = 1e7 + 0721;
bool pos[N];
int d, I;

int main() {
	freopen("drop.in", "r", stdin);
	freopen("drop.out", "w", stdout);
	
	scanf("%d%d", &d, &I);
	int x;
	for (int i = 1; i <= I; ++i) {
		x = 1;
		for (int j = 1; j < d; ++j) {
			if (pos[x]) {
				pos[x] = !pos[x];
				x = rs;
			} else {
				pos[x] = !pos[x];
				x = ls;
			}
		}
	}
	printf("%d",x);
	
	return 0;
}

补:实际上一个点被经过两次等于没被经过 所以只需要看第I个点之前有多少点到达即可 复杂度O(logD)

posted @ 2023-05-18 21:13  Steven24  阅读(13)  评论(0编辑  收藏  举报