1012模拟赛复盘

考试安排

8:00 - 8:30:看T1,没有太多思路(实际就是套路题),一直在完善我的思路
8:50 - 9:10:战略放弃T1, 开T2,先打50pts的暴力,等会拍用
9:20 - 9:50 :爆炸,有细节错误, 调
9:50-10:10:调出来了,直接看T4
10:10 - 10:20 :迅速码完T4 35pts
10:10 - 10:50 : 重看T1,有思路了,开码
10:50 - 12:00 :调, 调, 调出来了


预期分数: 100 + 50 + 0 + 60 = 210
分数: 0 + 0 + 0 + 60 = 60pts

出现问题

1.不懂得取舍, 在T1没有想到非常容易得实现方式时就匆匆开打
2.后面的暴力分没有保证完全拿到
3.心态问题,T1在前1个小时打不出来就爆,感觉是一个很大的问题

解决or收获?

T1一般不考察难的知识点,要仔细思考题目的性质,或者反着做,技巧性的东西一定要记清
题目的部分分不一定是递增的,本题的80分感觉比T3的80分好写多了
要稳住心态,不管T1有没有过掉,暴力拿满分数一定不低

新涂色游戏

在这里插入图片描述
在这里插入图片描述
回头看这道题其实非常简单

对于涂色,整行或整列,则最后一定有一整行或一整列为一个颜色,反着做,再将操作reverse就可以了

//正着做不好做,反着删 
#include<bits/stdc++.h>
using namespace std;
#define LL long long 
#define PII pair<int, int>
const int MAX = 1100;
int n, a[MAX][MAX], tot;
bool can[2 * MAX];
int num[2 * MAX][2 * MAX], kind[2 * MAX];
PII ans[2 * MAX];
void work(int id) {
	if(id <= n) {
		int co;
		for(int i = 1; i <= n; i++) {
			if(a[id][i] != 0 && a[id][i] != -1) {
				co = a[id][i];
				num[n + i][a[id][i]]--;
				if(num[n + i][a[id][i]] == 0) kind[n + i] -= 1;
				a[id][i] = 0;
			}
		}
		ans[++tot] = {(PII){id, co}};
	} else {
		int co;
		id = (id % n == 0) ? (n) : (id % n);
		for(int i = 1; i <= n; i++) {
			if(a[i][id] != 0 && a[i][id] != -1) {
				co = a[i][id];
				num[i][a[i][id]]--;
				if(num[i][a[i][id]] == 0) kind[i] -= 1;
				a[i][id] = 0;
			}
		}
		ans[++tot] = {(PII){id + n, co}};
	}
}
int main() {
	freopen("game.in","r",stdin);
	scanf("%d", &n);
	for(int i = 1; i <= n; i++) 
		for(int j = 1; j <= n; j++) {
			scanf("%d", &a[i][j]);
			if(a[i][j] == 0) a[i][j] = -1; 
		} 
	for(int i = 1; i <= n; i++) {
		bool flg = 1;
		for(int j = 1; j <= n; j++) {
			if(a[i][j] == -1) {
				flg = 0;
				break;	
			} else {
				if(num[i][a[i][j]] == 0) kind[i]++;
				num[i][a[i][j]]++;
			}
		}
		can[i] = flg; 
	}
	for(int j = 1; j <= n; j++) {
		bool flg = 1;
		for(int i = 1; i <= n; i++) {
			if(a[i][j] == -1) {
				flg = 0;
				break;
			} else {
				if(num[n + j][a[i][j]] == 0) kind[n + j]++;
				num[n + j][a[i][j]]++;
			}
		}
		can[n + j] = flg;
	}
	for(int i = 1; i <= 2 * n; i++) {
		for(int j = 1; j <= 2 * n; j++) {
			if(can[j] == 1 && kind[j] == 1) {
				work(j);
				can[j] = 0;
				break;
			}
		}
	}
	reverse(ans + 1, ans + 1 + tot);
	printf("%d\n", tot);
	for(int i = 1; i <= tot; i++) {
		printf("%d %d\n", ans[i].first, ans[i].second);
	}
	return 0;
}

新-滑动窗口

在这里插入图片描述
在这里插入图片描述
典中典, ∑ l i ≤ 1 0 6 \sum li \le10^{6} li106对于滑块顶到最左边与滑块顶到最右边相交的直接暴力做,如果不交,直接差分最大值,细节较多

#include<bits/stdc++.h>
using namespace std;
#define LL long long 
const int MAX = 1e6 + 70;
int n, w, l[MAX];
LL ans[MAX], cha[MAX];
LL a[MAX],b[MAX]; //统计
deque<LL> q;
void work(int h) {
	LL maxx = 0;
	vector<LL> Now; 
	Now.clear();
	Now.push_back(0); 
	for(int j = 1; j <= l[h]; j++) {
		LL x; scanf("%lld", &x);
		b[j] = x;
		maxx = max(maxx, x);
		Now.push_back(x);
	} 
	if(l[h] < w - l[h] + 1) { //不交 
		LL Max = 0;
		for(int i = 1; i <= l[h]; i++) {
			Max = max(Max, Now[i]);
			ans[i] += Max;
		}
		Max = 0;
		for(int i = w; i >= w - l[h] + 1; i--) {
			Max = max(Max, Now[l[h] - (w - i)]);
			ans[i] += Max; 		
		}
		cha[l[h] + 1] += maxx;
		cha[w - l[h] + 1] -= maxx;
	} else { //香蕉 
		memset(a, 0xcf, sizeof(a));
		while(!q.empty()) q.pop_back();
		int len = w - l[h] + 1;
		for(int i = 1; i <= l[h]; i++) {
			while(!q.empty() && i - q.front() + 1 > len) q.pop_front();
			while(!q.empty() && Now[q.back()] < Now[i]) q.pop_back();
			q.push_back(i);
			a[i] = max(a[i], Now[q.front()]);
		}
		for(int i = 1; i <= w - l[h]; i++) a[i] = max(a[i], 1LL * 0);
		while(!q.empty()) q.pop_back();
		Now.clear(); 
		for(int i = 0; i <= w - l[h]; i++) Now.push_back(0);
		for(int i = w - l[h] + 1; i <= w; i++) Now.push_back(b[i - (w - l[h])]);
		for(int i = w; i >= w - l[h] + 1; i--) {
			while(!q.empty() && q.front() - i + 1 > len) q.pop_front();
			while(!q.empty() && Now[q.back()] < Now[i]) q.pop_back();
			q.push_back(i);
			a[i] = max(a[i], Now[q.front()]);
		}	
		for(int i = l[h] + 1; i <= w; i++) {
			a[i] = max(a[i], 1LL * 0);
		} 
		for(int i = 1; i <= w; i++) {
			ans[i] += a[i];
		}
	}
}
int main() {
	freopen("windows.in","r",stdin);
	scanf("%d%d", &n, &w);
	for(int i = 1; i <= n; i++) {
		scanf("%d", &l[i]);
		work(i);
	}
	for(int i = 1; i <= w; i++) {
		cha[i] += cha[i - 1];
		printf("%lld ", ans[i] + cha[i]);
	}
	return 0;
}
/*
1 5
2 -10 10
*/


小明去旅游

在这里插入图片描述
在这里插入图片描述

目前还不会,先锅着

Heavy and Frail

在这里插入图片描述
在这里插入图片描述
35pts,二进制分组背包暴力跑

80pts? 发现只有单点修改,其他不变,跑一个前缀背包,跑一个后缀背包,对于查询,将前后两个背包合并,再插入

//根据m非常小的性质, 且是单点修改, 完全可以维护前i个数的背包,与后i个数的背包, 查询时暴力合并,复杂度 m*m*q  * logc 
#include<bits/stdc++.h>
using namespace std;
#define LL long long 
const int MAX = 5100;
int n, m, q;
LL val[MAX], v[MAX], num[MAX];
LL f_pre[MAX][810], f_back[MAX][810]; //表示前i个数的背包, 后i个数的背包 
LL f[810], ans[MAX * 10];
struct made {
	int id; 
	LL x, y, z;
	int whr;
}ask[MAX * 10];
bool mycmp(made X, made Y) {
	return X.id < Y.id;
}
int main() {
	freopen("reflect.in","r",stdin);
	scanf("%d%d", &n, &m);
	for(int i = 1; i <= n; i++) scanf("%lld",&val[i]);
	for(int i = 1; i <= n; i++) scanf("%lld", &v[i]);
	for(int i = 1; i <= n; i++) scanf("%lld", &num[i]); 
	scanf("%d", &q);
	for(int i = 1; i <= q; i++) {
		scanf("%d%lld%lld%lld", &ask[i].id, &ask[i].x, &ask[i].y, &ask[i].z);
		ask[i].whr = i;
	}  
	sort(ask + 1, ask + 1 + q, mycmp);
	for(int i = 1; i <= n; i++) {
		for(int j = 1; j <= m; j++) f_pre[i][j] = f_pre[i - 1][j];
		int Num = num[i], k = 1;
		while(k <= Num) {
			LL V = k * v[i]; LL VAL = k * val[i]; 
			for(int j = m; j >= V; j--) f_pre[i][j] = max(f_pre[i][j], f_pre[i][j - V] + VAL);
			Num -= k;
			k *= 2;
		}
		if(Num != 0) {
			LL V = Num * v[i]; LL VAL = Num * val[i];
			for(int j = m; j >= V; j--) f_pre[i][j] = max(f_pre[i][j], f_pre[i][j - V] + VAL);
		}
	}
	for(int i = n; i >= 1; i--) {
		for(int j = 1; j <= m; j++) f_back[i][j] = f_back[i + 1][j];
		int Num = num[i], k = 1;
		while(k <= Num) {
			LL V = k * v[i]; LL VAL = k * val[i]; 
			for(int j = m; j >= V; j--) f_back[i][j] = max(f_back[i][j], f_back[i][j - V] + VAL);
			Num -= k;
			k *= 2;
		}
		if(Num != 0) {
			LL V = Num * v[i]; LL VAL = Num * val[i];
			for(int j = m; j >= V; j--) f_back[i][j] = max(f_back[i][j], f_back[i][j - V] + VAL);
		}
	}	
	for(int i = 1; i <= q; i++) {
		for(int j = 1; j <= m; j++) f[j] = 0;
		for(int j = 1; j <= m; j++) {
			for(int k = 0; k <= j; k++) {
				f[j] = max(f[j], f_pre[ask[i].id - 1][j - k] + f_back[ask[i].id + 1][k]);
			}
		}
		int Num = ask[i].z, k = 1;
		while(Num >= k) {
			LL V = ask[i].y * k; LL VAL = ask[i].x * k;
			for(int j = m; j >= V; j--) f[j] = max(f[j], f[j - V] + VAL);
			Num -= k;
			k *= 2;
		}
		if(Num) {
			LL V = ask[i].y * Num; LL VAL = ask[i].x * Num;
			for(int j = m; j >= V; j--) f[j] = max(f[j], f[j - V] + VAL);
		}
		ans[ask[i].whr] = f[m];
	}
	for(int i = 1; i <= q; i++) printf("%lld\n", ans[i]);
	return 0;
}

100pts,只有单点修改,前后缀的合并 m 2 m^2 m2没有拓展性,思考如果分治去做, ( l , r ) (l, r) (l,r)代表到 ( l , r ) (l,r) (l,r)区间内除了 ( l , r ) (l,r) (l,r)都已经被加入背包,到 ( x , x ) (x, x) (x,x)时便统计答案,时间复杂度 O ( n ∗ m ∗ l o g n 2 + m q ) O(n*m*log_n^2+mq) O(nmlogn2+mq)
重复计算,分治

#include<bits/stdc++.h>
using namespace std;
#define LL long long 
const int MAX = 5010;
int n, m, q;
LL val[MAX], v[MAX], num[MAX], ans[MAX * 10];
LL f[900];
struct made { 
	int id;
	LL num, v, val; 
};
vector<made> ask[MAX];
void Nowwork(int l, int r) {
	for(int j = l; j <= r; j++) {
		int Num = num[j], k = 1;
		while(k <= Num) {
			LL V = k * v[j], VAL = val[j] * k;
			for(int j = m; j >= V; j--) f[j] = max(f[j], f[j - V] + VAL);
			Num -= k;
			k *= 2;
		}
		if(Num) {
			LL V = Num * v[j], VAL = val[j] * Num;
			for(int j = m; j >= V; j--) f[j] = max(f[j], f[j - V] + VAL);
		}
	}
}
void work(int x) {
	LL fnow[802];
	for(auto y : ask[x]) {
		int Num = y.num, k = 1;
		for(int i = 0; i <= m; i++) fnow[i] = f[i]; 
		while(k <= Num) {
			LL V = k * y.v, VAL = k * y.val;
			for(int i = m; i >= V; i--) f[i] = max(f[i - V] + VAL, f[i]);
			Num -= k;
			k *= 2;
		}
		if(Num) {
			LL V = Num * y.v, VAL = Num * y.val;
			for(int i = m; i >= V; i--) f[i] = max(f[i - V] + VAL, f[i]);
		}
		ans[y.id] = f[m];
		for(int i = 0; i <= m; i++) f[i] = fnow[i];
	}
}
void slove(int l, int r) {
	if(l == r) {
		work(l);
		return ;
	}
	int mid = (l + r) >> 1;
	LL fnow[810];
	for(int i = 0; i <= m; i++) fnow[i] = f[i];
	Nowwork(mid + 1, r);
	slove(l, mid);
	for(int i = 0; i <= m; i++) f[i] = fnow[i];
	Nowwork(l, mid);
	slove(mid + 1, r); 
}
int main() {
	freopen("reflect.in","r",stdin);
	scanf("%d%d", &n, &m);
	for(int i = 1; i <= n; i++) scanf("%lld", &val[i]);
	for(int i = 1; i <= n; i++) scanf("%lld", &v[i]);
	for(int i = 1; i <= n; i++) scanf("%lld", &num[i]);
	scanf("%d", &q);
	for(int i = 1; i <= q; i++) {
		int t; LL x, y, z; scanf("%d%lld%lld%lld", &t, &x, &y, &z);
		made Now; Now.id = i, Now.num = z, Now.v = y, Now.val = x;
		ask[t].push_back(Now);
	}
	slove(1, n);
	for(int i = 1; i <= q; i++) {
		printf("%lld\n", ans[i]);
	}
	return 0;
}

posted @ 2023-10-13 19:25  Nogtade  阅读(2)  评论(0编辑  收藏  举报  来源