CSP2020试题解法与总结(游记)

Day-1

考试前一天晚,没上竞赛课,教练叫我们在家做题,别说不愧是信心赛题目都海星,做完后就睡觉了不过有一道题数据好像错了

Day0

考前

早上6:00就起床了,可能是想跟着大部队吧,没有直接去考场而是去了学校,一行人都上了车,不过初一是在是太吵了(跟我们初一时一样
上了车跟一旁的yzk一起背了一下模板然后差不多就到了NK。不得不说NK的硬件真的要好亿一些。

考前教练反复跟我们说一定要保存,一定要调整好心态。(不然就是给CCF送钱

考时

拿到第一道题一眼看穿就是从大到小看小于2的几次方,之后再减,打完过完样例就跑了
T1.马蜂清奇

#include<cstdio>

int Pow(int f) {
  int sum = 2, ans = 1;
  while(f) {
  	if(f & 1) {
  		ans *= sum;
  	}
  	sum *= sum;
  	f >>= 1;
  }
  return ans;
}

int main() {
//	freopen("power.in", "r", stdin);
//	freopen("power.out", "w", stdout);
  int n, sum = 1, tot = 0, cnt = 0, g;
  scanf("%d", &n);
  g = n;
  while(sum < n) {
  	sum *= 2;
  	tot ++;
  }
  for(int i = tot; i >= 1; i --) {
  	int s = Pow(i);
  	if(s <= g) {
  		g -= s;
  	}
  } if(g != 0) {
  	printf("%d", -1);
  } else {
  	for(int i = tot; i >= 1; i --) {
  		int s = Pow(i);
  		if(s <= n) {
  			n -= s;
  			printf("%d ", s);
  		}
  	} 
  }
  return 0;
}

T2.
考试的时候没有看数据范围成绩<=600,于是就打了一个n^2的略带优化的代码就草草了事,考后才发现直接桶排(600n)就可以了
考试时的代码

#include<cstdio>
#include<algorithm>
using namespace std;

struct lx {
   int l, id;
}a[100005];

int Max(int x, int y) { return x > y ? x : y; }
int Min(int x, int y) { return x < y ? x : y; }

bool cmp(lx x, lx y) {
   if(x.l == y.l) {
   	return x.id < y.id;
   } return x.l > y.l;
}

int main() {
//	freopen("live.in", "r", stdin);
//	freopen("live.out", "w", stdout);
   int n, w;
   scanf("%d %d", &n, &w);
   for(int i = 1; i <= n; i ++) {
   	scanf("%d", &a[i].l);
   	a[i].id = i;
   }
   sort(a + 1, a + 1 + n, cmp);
   for(int i = 1; i <= n; i ++) {
   	int tot = i * w / 100, cnt = 0, ans = 0x7f7f7f7f;
   	tot = Max(tot, 1);
   	for(int j = 1; j <= n; j ++) {
   		if(cnt == tot) break;
   		if(a[j].id <= i) {
   			cnt ++;
//				printf("%d %d %d\n", a[j].l, a[j].id, i);
   			ans = Min(ans, a[j].l);
   		}
   	}
   	printf("%d ", ans);
   }
   return 0;
}

正解

#include<cstdio>
#include<algorithm>
using namespace std;

struct lx {
	int l, id;
}a[100005];

int s[605];
int Max(int x, int y) { return x > y ? x : y; }
int Min(int x, int y) { return x < y ? x : y; }

bool cmp(lx x, lx y) {
	if(x.l == y.l) {
		return x.id < y.id;
	} return x.l > y.l;
}

int main() {
//	freopen("live.in", "r", stdin);
//	freopen("live.out", "w", stdout);
	int n, w;
	scanf("%d %d", &n, &w);
	for(int i = 1; i <= n; i ++) {
		scanf("%d", &a[i].l);
		s[a[i].l] ++;
//		printf("%d %d\n", a[i].l, s[a[i].l]);
		int tot = i * w / 100, sum = 0;
		tot = Max(tot, 1);
		for(int j = 600; j >= 0; j --) {
			if(s[j]) {
				sum += s[j];
//				printf("%d %d %d\n", i, j, s[j]);
				if(sum >= tot) {
					printf("%d ", j);
					break;
				}
			}
		}
	}
	return 0;
}

T4.
考试的时候可能是太浮躁了,没有认真想就先开始打了代码,打了dfs爆搜,和瞎搞最短路SPFA两种,中间也想到是DP,当时想的时候认为跟数字三角形很像,但总觉得有后效型降智了,于是就没有认真打,其实只要从左向右枚举,每次只考虑(上面,左面,下面)的情况就不会有后效性了,于是就可以在内层循环从上到下,从下到上分别DP,讨论两种情况就可以了方程是:
dp[i][j][0] = Max(dp[i - 1][j][0], Max(dp[i][j - 1][0], dp[i][j - 1][1])) + a[i][j];
dp[i][j][1] = Max(dp[i + 1][j][1], Max(dp[i][j - 1][0], dp[i][j - 1][1])) + a[i][j];

#include<cstdio>
#include<cstring>
#define int long long

int dp[1005][1005][5];
int a[1005][1005];

int Max(int x, int y) { return x > y ? x : y; }

signed main() {
	int n, m;
	scanf("%lld %lld", &n, &m);
	for(int i = 1; i <= n; i ++) {
		for(int j = 1; j <= m; j ++) {
			scanf("%lld", &a[i][j]);
		}
	} memset(dp, -0x3f, sizeof(dp));
	dp[0][1][0] = 0;
	for(int i = 1; i <= n; i ++) dp[i][1][0] = a[i][1] + dp[i - 1][1][0];
	for(int j = 2; j <= m; j ++) {
		for(int i = 1; i <= n; i ++) {
			dp[i][j][0] = Max(dp[i - 1][j][0], Max(dp[i][j - 1][0], dp[i][j - 1][1])) + a[i][j];
		}
		for(int i = n; i >= 1; i --) {
			dp[i][j][1] = Max(dp[i + 1][j][1], Max(dp[i][j - 1][0], dp[i][j - 1][1])) + a[i][j];
		}
	}
	printf("%lld", Max(dp[n][m][1], dp[n][m][0]));
}

CSP-J就这样结束了,考得不是很好,但还是学到了很多,明白了考试时一定要看数据范围(面向数据编程)懂得都懂,打代码时一定要慢,想好了在答题,不然我自己就是前车之鉴。


版权声明:本文为lakafl原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。