GESP真题解析 (选取一部分9月) & 如何速通GESP?两篇文章教会你!(下)(通过题目来讲)

六级

[GESP202409 六级] 小杨和整数拆分

题目描述

小杨有一个正整数 n n n,小杨想将它拆分成若干完全平方数的和,同时小杨希望拆分的数量越少越好。

编程计算总和为 n n n 的完全平方数的最小数量。

输入格式

输入只有一行一个正整数 n n n

输出格式

输出一行一个整数表示答案。

样例 #1

样例输入 #1
18
样例输出 #1
2

提示

数据规模与约定

对全部的测试数据,保证 1 ≤ n ≤ 1 0 5 1 \leq n \leq 10^5 1n105

这道题是我之前讲过的DP,相信不难看出吧,六级考的都是简单一维DP,这里用 f ( i ) f(i) f(i) 表示总和为 i i i 的完全平方数的最小数量,转移不难,直接放代码,具体看:

#include 
using namespace std;
int n;
int f[100100];

int main() {
	scanf("%d", &n);
	memset(f, 0x3f, sizeof(f));
	f[1] = 1, f[0] = 0;
	for (int i = 2; i <= n; i++) {
		for (int j = sqrt(i); i - int(j * j) <= i && j > 0; j--) {
			f[i] = min(f[i], f[i - int(j * j)] + 1);
		}
	}
	printf("%d", f[n]);
	return 0;
}

树的知识稍后扩展,暂不做讲解。

七级

[GESP202409 七级] 矩阵移动

题目描述

小杨有一个有一个 n × m n \times m n×m 的矩阵,仅包含 01? 三种字符。矩阵的行从上到下编号依次为 1 , 2 , … , n 1,2,\dots, n 1,2,,n,列从左到右编号依次为 1 , 2 , … , m 1, 2, \dots, m 1,2,,m。小杨开始在矩阵的左上角 ( 1 , 1 ) (1,1) (1,1),小杨只能向下或者向右移动,最终到达右下角 ( n , m ) (n, m) (n,m) 时停止,在移动的过程中每经过一个字符 1 得分会增加一分(包括起点和终点),经过其它字符则分数不变。小杨
的初始分数为 0 0 0 分。

小杨可以将矩阵中不超过 k k k 个字符 ? 变为字符 1。小杨在修改矩阵后,会以最优的策略从左上角移动到右下角。他想
知道自己最多能获得多少分。

输入格式

第一行包含一个正整数 t t t,代表测试用例组数,接下来是 t t t 组测试用例。对于每组测试用例,一共 n + 1 n + 1 n+1 行。

第一行包含三个正整数 n , m , x n, m, x n,m,x,含义如题面所示。
之后 n n n 行,每行一个长度为 m m m 的仅含 01x? 的字符串。

输出格式

对于每组测试用例,输出一行一个整数,代表最优策略下小杨的得分最多是多少。

样例 #1

样例输入 #1
2
3 3 1
000
111
01?
3 3 1
000
?0?
01?
样例输出 #1
4
2

提示

样例 1 解释

对于第二组测试用例,将 ( 1 , 1 ) (1,1) (1,1) 或者 ( 3 , 3 ) (3,3) (3,3) 变为 1 1 1 均是最优策略。

数据规模与约定
子任务编号 数据点占比 t t t n , m n,m n,m x x x
1 1 1 30 % 30\% 30% ≤ 5 \leq 5 5 ≤ 10 \le 10 10 = 1 =1 =1
2 2 2 30 % 30\% 30% ≤ 10 \le 10 10 ≤ 500 \le 500 500 ≤ 30 \le 30 30
3 3 3 40 % 40\% 40% ≤ 10 \le 10 10 ≤ 500 \le 500 500 ≤ 300 \le 300 300

对全部的测试数据,保证 1 ≤ t ≤ 10 1 \leq t \leq 10 1t10 1 ≤ n , m ≤ 500 1 \leq n,m \leq 500 1n,m500 1 ≤ x ≤ 300 1 \leq x \leq 300 1x300,保证所有测试用例 n × m n \times m n×m 的总和不超过 2.5 × 1 0 5 2.5 \times 10^5 2.5×105

可以看,算比较简单的DP吧,很暴力, f ( i , j , k ) f(i,j,k) f(i,j,k),多一维处理 ? ? ?。代码:

#include
using namespace std;
char a[510][510];
int f[510][510][310];
int main(){
	int t;
	scanf("%d",&t);
	while(t--){
		int n,m,k;
		cin>>n>>m>>k;
		for(int i=1;i <= n;i++){
			for(int j=1;j <= m;j++){
				cin>>a[i][j];
			}
		}
		memset(f,0,sizeof(f));
		for(int i=1;i <= n;i++){
			for(int j=1;j <= m;j++){
				for(int x=0;x <= k;x++){
					if(a[i][j]!='?'){
						f[i][j][x]=max(f[i-1][j][x],f[i][j-1][x])+1;
						if(a[i][j]=='0') f[i][j][x]--;
					}else{
						f[i][j][x]=max(f[i-1][j][x],f[i][j-1][x]);
						if(x!=0)f[i][j][x]=max(f[i][j][x],max(f[i-1][j][x-1],f[i][j-1][x-1])+1);
					}
				}
			}
		}
		int ans=0;
		for(int i=0;i <= k;i++){
			ans=max(ans,f[n][m][i]);
		}
		printf("%d\n",ans);
	}
	
	
	return 0;
}

T2后面图论讲,会在12月7日前。

八级

[GESP202409 八级] 手套配对

题目描述

小杨有 n n n 对不同的手套,每对手套由左右各一只组成。

小杨想知道从中取出 m m m 只手套,恰好包含 k k k 对手套的情况有多少种。

小杨认为两种取出的情况不同,当且仅当两种情况取出的手套中存在不同的手套(同一对手套的左右手也视为不同的手套)。

输入格式

本题单个测试点内由多组测试数据。第一行是一个整数 t t t,表示测试用例数量。接下来是 t t t 组测试用例,每组一行。

每组数据只有一行三个正整数 n , m , k n,m,k n,m,k,表示手套数量、取出的手套数和目标对数。

输出格式

对每组数据,输出一行一个整数表示答案对 1 0 9 + 7 10^9 + 7 109+7 取模的结果。

样例 #1

样例输入 #1
2
5 6 2
5 1 5
样例输出 #1
120
0

提示

子任务 占比 t t t n n n m m m k k k
1 1 1 30 % 30\% 30% ≤ 5 \leq 5 5 1000 1000 1000 ≤ 3 \le 3 3 = 1 =1 =1
2 2 2 30 % 30\% 30% ≤ 5 \leq 5 5 ≤ 5 \leq 5 5 ≤ 10 \leq 10 10 ≤ 5 \leq 5 5
3 3 3 40 % 40\% 40% 1 0 5 10^5 105 1000 1000 1000 2000 2000 2000 2000 2000 2000

对全部的测试数据,保证 1 ≤ t ≤ 1 0 5 1 \leq t \leq 10^5 1t105 1 ≤ n ≤ 1000 1 \leq n \leq 1000 1n1000 1 ≤ m ≤ 2 × n 1 \leq m \leq 2 \times n 1m2×n 1 ≤ k ≤ n 1 \le k \le n 1kn

∵ \because 恰好包含 k k k 对手套的情况。 ∴ \therefore C n k C_n^k Cnk,则答案为 C n k ⋅ C 2 ( n − k ) m − 2 k C_n^k·C_{2(n-k)}^{m-2k} CnkC2(nk)m2k,不作详细代码。

树上&图上DP下章讲!

你可能感兴趣的:(算法,数学建模)