2024.8.30校测

T1

题目描述

物理老师 YJ 有一个长杆天平,天平的两臂长均为 15,将长杆看作 x 轴,则平衡点在 0 位置处,负数位置在左臂上,正数位置在右臂上。长杆上有 n 个位置有挂钩可以挂秤砣。YJ 有 m 个秤砣,质量分别为 gi,每个挂钩可以不挂也可以挂任意个秤砣。YJ 想要知道,在使用所有秤砣的条件下,有多少种不同的挂秤砣的方案,可以使得天平平衡?问题太过复杂,仅凭物理知识难以解决,所以请你来帮助他。

天平的平衡条件是所有秤砣的位置质量之和为 0。例如有质量为 2,3,4 的秤砣分别挂在 3,2,3 位置处,则 2×(3)+3×(2)+4×3=0,天平是平衡的。

输入格式

第一行两个数 n,m。表示挂钩的数目和秤砣的数目。

第二行 n 个不同且递增的数,第 i 个数表示第 i 个挂钩的位置,数的范围在 [15,15] 内。

第三行 m 个不同且递增的数,第 i 个数表示第 i 个秤砣的质量,数的范围在 [1,25] 内。

输出格式

一个整数,代表能使得天平平衡的方案数。

输入样例

2 4
-2 3
3 4 5 8

输出样例

2

样例解释

方案 1(2)×(3+4+5)+3×8=0

方案 2(2)×(4+8)+3×(3+5)=0

数据规模

对于 10% 数据,2n,m4

对于 100% 数据, 2n,m20

题解

考虑可以组合出的重量在 75007500 之间,我们可以枚举这个重量,把这个重量作为容量,再用背包做就行了。

完整代码

#include <bits/stdc++.h>
using namespace std;
#define int long long 
const int N = 1.5e4 + 9, M = 39;
int dp[M][N], w[N], p[N], n, m;
signed main(){
	freopen("balance.in", "r", stdin);
	freopen("balance.out", "w", stdout);
	scanf("%lld%lld", &n, &m);
	for(int i = 1; i <= n; i++)
		scanf("%lld", &p[i]);
	for(int i = 1; i <= m; i++)
		scanf("%lld", &w[i]);
	dp[0][7500] = 1;
	for(int i = 1; i <= m; i++)
		for(int j = 1; j <= n; j++)
			for(int k = 0; k <= 15000; k++){
				if(k - w[i] * p[j] < 0 || k - w[i] * p[j] > 15000)
					continue;
				dp[i][k] += dp[i - 1][k - w[i] * p[j]];
			}
	printf("%lld", dp[m][7500]);
	return 0;
} 

T2

题目描述

山峰数是指数字排列中不存在山谷(先降后升)的数,例如 0,5,13,12321 都是山峰数,101,1110000111 都不是山峰数。

现给出 n 个数,请依次判断它们是否为山峰数,如果不是,输出 -1。如果是,求出比它小的数中有多少个山峰数。

输入格式

第一行一个数 n,表示询问数目。

接下来 n 行,每一行一个数 x,表示询问的数。

输出格式

输出有 n 行,x 如果不是山峰数,输出 -1x 如果是山峰数,则输出有多少个比它小的山峰数。

输入样例

5
10
55
101
1000
1234321

输出样例

10
55
-1
715
94708

数据规模

对于 20 数据, x106

对于 100 数据, n10,x1060

题解

“为什么要攀登?因为山就在那里。”

非常板的数位 DP,在 DFS 时多记录一下之前是否下降过,如果下降过就不能再上升,其它跟普通数位 DP 一样。

完整代码

#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 69;
int a[N], dp[N][10][2][2], T, len;
char ch[N];
int dfs(int pos, int pre, int down, int lim){
	if(pos == len + 1)
		return 1;
	if(dp[pos][pre][down][lim] != -1)
		return dp[pos][pre][down][lim];
	int up = lim ? a[pos] : 9, ans = 0;
	for(int i = 0; i <= up; i++){
		if(!down){
			if(i < pre)
				ans += dfs(pos + 1, i, 1, lim && i == up);
			else
				ans += dfs(pos + 1, i, 0, lim && i == up);
		} else if(i <= pre)
			ans += dfs(pos + 1, i, 1, lim && i == up);
	}
	return dp[pos][pre][down][lim] = ans;
}
signed main(){
	freopen("hill.in", "r", stdin);
	freopen("hill.out", "w", stdout);
	scanf("%lld", &T);
	while(T--){
		scanf("%s", ch);
		len = strlen(ch);
		for(int i = 0; i < len; i++)
			a[i + 1] = ch[i] - '0';
		bool flag = false, flag2 = false;
		for(int i = 2; i <= len; i++){
			if(a[i - 1] > a[i])
				flag = true;
			if(flag && a[i] > a[i - 1]){
				flag2 = true;
				break;
			}
		}	
		if(flag2)
			printf("-1\n");
		else {
			memset(dp, -1, sizeof(dp));
			printf("%lld\n", dfs(1, 0, 0, 1) - 1);
		}	
	}
	return 0;
} 

T3

题目描述

有一个 4×N 的木板需要粉刷,第 ij 列的颜色记为 Ai,j。有 256 种颜色,记为 0255,为了使得粉刷比较好看,粉刷需要满足如下要求:

  1. Ax,yAx,y1

  2. 有一些指定的 (x1,y1)(x2,y2),要求 Ax1,y1=Ax2,y2

请问有多少种满足要求的粉刷方式?输出答案的最后 5 位即可。

输入格式

第一行两个数 n,m,表示木板的长度,和指定规则的条目个数。

接下来 m 行,每行四个数 x1,y1,x2,y1,此规则表示 Ax1,y1 需要等于 Ax2,y2

输出格式

一个整数,表示答案的末 5 位。

输入样例1

1 0

输出样例1

67296

输入样例2

1 3
1 1 2 1
1 1 3 1
4 1 3 1

输出样例2

00256

提示

输出可以使用 %05d 输出。

数据规模

对于 30% 数据,n3,m=0

对于 100% 数据,1n15,0M100,x1,x24,y1,y2n

T4

题目描述

有一个 N×M 的棋盘,要在上面摆上 knight,每个格子可以放至多一个 knight。

knight 的攻击范围如下图:

所有 knight 不能互相攻击,请问总共有多少可行的摆法?答案对 1000000007 取模。

输入格式

第一行个数 t,表示测试的组数。

接下来 t 组,每组两个整数,nm

输出格式

一共 t 行,第 i 行表示第 i 组的答案。

输入样例

4
1 2
2 2
3 2
3 31415926

输出样例

4
16
36
933912086

数据规模

对于 70% 数据,m100

对于 100% 数据,t10,n3,m109

题解

由于 n 比较小,所以考虑状压的思想,有马的位置标记为 1,无马的位置标记为 0,将两列压成一个二进制数,由于马不能相互攻击,因此这样的状态有 36 种。

那么原问题就相当于是将 m1 个这样的两排 每两排重叠一排地拼在一起,马不能相互攻击,重叠的两排有相同的一排,有多少种方法可以拼出整个棋盘。

比如,下面的两个局面可以拼在一起:

拼成:

如果我们将有相同一排,且重叠一排拼在一起后马不能互相攻击的局面建立一条无向边,用邻接矩阵存图。

现在有一个重要结论:邻接矩阵的 n 次方中 Ai,j 表示 ij 的不同路径中长度为 n 的路径条数 (我不会证qwq)

那么我们只用将这个邻接矩阵的 m1 次方算出来,将矩阵中第一排每个数加起来就是答案。

完整代码

#include <bits/stdc++.h>
using namespace std;
#define int long long 
const int P = 1000000007;
int n, cnt;
int rev[(36 + 1)];
struct Mat{
	int a[(36 + 1)][(36 + 1)];
	void Mat0(){
		for(int i = 1; i <= cnt; ++ i)
			for(int j = 1; j <= cnt; ++ j)
				a[i][j] = 0;
	}
	void Mat1(){
		for(int i = 1; i <= cnt; ++ i){
			for(int j = 1; j <= cnt; ++ j)
				a[i][j] = 0;
			a[i][i] = 1;
		}
	}
} x, ansmat;
Mat operator * (Mat &s, Mat &t){
	Mat res;
	res.Mat0();
	for(int i = 1; i <= cnt; ++ i)
		for(int j = 1; j <= cnt; ++ j)
			for(int k = 1; k <= cnt; ++ k)
				res.a[i][j] = (res.a[i][j] + s.a[i][k] * t.a[k][j] % P) % P;
	return res;
}
Mat Qpow(Mat s, int k){
	Mat res;
	res.Mat1();
	while(k){
		if(k & 1)
			res = s * res;
		s = s * s;
		k >>= 1;
	}
	return res;
}

int Check(int s){//判断局面是否合法
	if(n == 1)
		return 1;
	if(n == 2){
		if((s & 1) == 1 && ((s >> 5) & 1) == 1)
			return 0;
		if(((s >> 1) & 1) == 1 && ((s >> 4) & 1) == 1)
			return 0;
		return 1;
	}
	if((s & 1) == 1){
		if(((s >> 5) & 1) == 1)
			return 0;
		if(((s >> 7) & 1) == 1)
			return 0;
	}
	if(((s >> 1) & 1) == 1){
		if(((s >> 6) & 1) == 1)
			return 0;
		if(((s >> 8) & 1) == 1)
			return 0;
	}
	if(((s >> 2) & 1) == 1){
		if(((s >> 3) & 1) == 1)
			return 0;
		if(((s >> 7) & 1) == 1)
			return 0;
	}
	if(((s >> 3) & 1) == 1)
		if(((s >> 8) & 1) == 1)
			return 0;
	if(((s >> 5) & 1) == 1)
		if(((s >> 6) & 1) == 1)
			return 0;
	return 1;
}
signed main(){
	freopen("knight.in", "r", stdin);
	freopen("knight.out", "w", stdout);
	int t;
	scanf("%lld", & t);
	while(t --){
		int m;
		scanf("%lld%lld", &n, &m);
		cnt = 0;
		for(int s = 0; s < (1 << (n << 1)); s++){
			if(n == 3 && (((s & 1) == 1 && ((s >> 5) & 1) == 1) || (((s >> 2) & 1) == 1 && ((s >> 3) & 1) == 1)))
				continue;
			rev[++cnt] = s;
		}
		x.Mat0();
		for(int i = 1; i <= cnt; i++)
			for(int j = 1; j <= cnt; j++)
				if((rev[j] % (1 << n)) == (rev[i] >> n) && Check(rev[i] | ((rev[j] >> n) << (n << 1))) == 1)//判断两个局面是否能重叠一排拼在一起
					x.a[i][j] = 1;
		ansmat = Qpow(x, m);//矩阵快速幂,此处必须m次方
		int ans = 0;
		for(int j = 1; j <= cnt; j++)
			ans = (ans + ansmat.a[1][j]) % P;
		printf("%lld\n", ans);
	}
	return 0;
}
posted @   JPGOJCZX  阅读(3)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示