2024.8.30校测
T1
题目描述
物理老师 YJ 有一个长杆天平,天平的两臂长均为
天平的平衡条件是所有秤砣的位置质量之和为
输入格式
第一行两个数
第二行
第三行
输出格式
一个整数,代表能使得天平平衡的方案数。
输入样例
2 4
-2 3
3 4 5 8
输出样例
2
样例解释
方案
方案
数据规模
对于
对于
题解
考虑可以组合出的重量在
完整代码
#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
题目描述
山峰数是指数字排列中不存在山谷(先降后升)的数,例如
现给出 -1
。如果是,求出比它小的数中有多少个山峰数。
输入格式
第一行一个数
接下来
输出格式
输出有 -1
。
输入样例
5
10
55
101
1000
1234321
输出样例
10
55
-1
715
94708
数据规模
对于
对于
题解
“为什么要攀登?因为山就在那里。”
非常板的数位 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
题目描述
有一个
-
。 -
有一些指定的
和 ,要求 。
请问有多少种满足要求的粉刷方式?输出答案的最后
输入格式
第一行两个数
接下来
输出格式
一个整数,表示答案的末
输入样例1
1 0
输出样例1
67296
输入样例2
1 3
1 1 2 1
1 1 3 1
4 1 3 1
输出样例2
00256
提示
输出可以使用 %05d
输出。
数据规模
对于
对于
T4
题目描述
有一个
knight 的攻击范围如下图:
所有 knight 不能互相攻击,请问总共有多少可行的摆法?答案对
输入格式
第一行个数
接下来
输出格式
一共
输入样例
4
1 2
2 2
3 2
3 31415926
输出样例
4
16
36
933912086
数据规模
对于
对于
题解
由于
那么原问题就相当于是将
比如,下面的两个局面可以拼在一起:
拼成:
如果我们将有相同一排,且重叠一排拼在一起后马不能互相攻击的局面建立一条无向边,用邻接矩阵存图。
现在有一个重要结论:邻接矩阵的
那么我们只用将这个邻接矩阵的
完整代码
#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;
}
本文来自博客园,作者:JPGOJCZX,转载请注明原文链接:https://www.cnblogs.com/JPGOJCZX/p/18422878
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】