A题 今
来源:2022年第五届广西大学生程序设计竞赛 A题Arrangement
考察:结构体排序(本周考点)
难度:橙题
本题考察结构体排序的使用,在之前的周测中也多出现过。在本题中,需要对综合难度优先排序,再考虑相等的一些其他情况。题目很模板,唯一的坑点可能就是没开long long可能会wa,数据范围到了1e6*1e6=1e12会爆int类型的。
#include<bits/stdc++.h>
#define endl '\n'
typedef long long ll;
const ll mod = 1e9 + 7;
using namespace std;
struct ss {
int id;
ll x, y;
ll sum;
}a[2020];
bool cmp(ss h1, ss h2) {
if (h1.sum == h2.sum) {
if (h1.x == h2.x) {
return h1.id < h2.id;
}
else {
return h1.x < h2.x;
}
}
else {
return h1.sum < h2.sum;
}
}
int main() {
int n;
cin >> n;
for (int i = 1; i <= n; i++) {
cin >> a[i].x;
}
for (int i = 1; i <= n; i++) {
cin >> a[i].y;
a[i].id = i;
a[i].sum = a[i].x * a[i].y;
}
sort(a + 1, a + 1 + n, cmp);
for (int i = 1; i <= n; i++) {
cout << (char)(a[i].id + 'A' - 1) << " ";
}
return 0;
}
B题 天
来源:[yLOI2019] 青原樱
考察:组合数学
难度:黄题
首先假设所有动力铁轨是一样的,那么 放置动力铁轨的方案数 * m!
把 个空位看作物品,此时这 m 个动力铁轨相当于隔板,一共有
个位置插入隔板。
可得 放置动力铁轨的方案数 =
由组合数公式可知
可得
#include<bits/stdc++.h>
#define endl '\n'
typedef long long ll;
const ll mod = 1e9 + 7;
using namespace std;
int main() {
ll n, m, p;
cin >> n >> m >> p;
ll ans = 1;
for (ll i = n - m * 2 + 2; i <= n - m + 1; i++) {
ans = ans * i % p;
}
cout << ans;
return 0;
}
C题 你
来源:NYOJ-1058 部分和问题
考察:暴力/dfs裸题(本周考点)
难度:橙题
本题为dfs的基本运用,因为数据范围不大,可以用深搜的方法来做,dfs选和不选的两种方案即可,做出来了的同学可以给自己加一点难度,再试一试若能凑出k,则输出选中的那些数字。本题数据范围比较小,也可以使用暴力求解,时间复杂度为O(2^n)大约为 1,048,576,完全不用担心超时。
#include<bits/stdc++.h>
#define endl '\n'
typedef long long ll;
const ll mod = 1e9 + 7;
using namespace std;
ll a[30];
ll n, m;
int f = 0;
void dfs(ll x, ll y) {
if (y == m) { //如果恰好为m,则标记一下。
f = 1;
return;
}
if (x == n + 1) {
return;
}
dfs(x + 1, y + a[x]); //选当前数
dfs(x + 1, y); //不选当前数
}
int main() {
cin >> n >> m;
for (int i = 1; i <= n; i++) {
cin >> a[i];
}
dfs(1, 0); //从第一个数开始深搜
if (f) {
cout << "Successful trade";
}
else {
cout << "Transaction failed";
}
return 0;
}
D题 加
来源:2021牛客寒假算法基础集训营6 I题贪吃蛇
考察:bfs裸题(本周考点)
难度:橙题
也是一道裸的bfs题,其实残影完全不影响,因为根据bfs的原理来说,是不会重复把走过的点加入队列的,其实残影只是个幌子,实则还是求起点到终点的最短距离即可,最后别忘了乘100换算单位。
#include<bits/stdc++.h>
#define endl '\n'
typedef long long ll;
const ll mod = 1e9 + 7;
const int maxn = 100 + 10;
using namespace std;
int n, m, sx, sy, ex, ey;
int dx[] = { 1,0,-1,0 };
int dy[] = { 0,1,0,-1 };
char mg[maxn][maxn];
bool vis[maxn][maxn];
struct node
{
int x, y;
int step;
};
void bfs()
{
node p;
p.x = sx; p.y = sy;
p.step = 0;
queue<node> q;
q.push(p);
vis[sx][sy] = 1;
while (!q.empty())
{
node tmp = q.front();
q.pop();
if (tmp.x == ex && tmp.y == ey)
{
cout << tmp.step * 100 << endl;
return;
}
for (int i = 0; i < 4; i++)
{
int xx = tmp.x + dx[i];
int yy = tmp.y + dy[i];
if (mg[xx][yy] != '#' && xx > 0 && yy > 0 && xx <= n && yy <= m && !vis[xx][yy])
{
node tp;
tp.x = xx;
tp.y = yy;
tp.step = tmp.step + 1;
vis[xx][yy] = 1;
q.push(tp);
}
}
}
cout << "-1" << endl;
}
int main()
{
while (cin >> n >> m)
{
memset(vis, 0, sizeof(vis));
cin >> sx >> sy;
cin >> ex >> ey;
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= m; j++)
{
cin >> mg[i][j];
}
}
bfs();
}
}
E题 训
来源:[NOI1999] 生日蛋糕
考察:dfs,剪枝优化(本周考点)
难度:绿题
搜索+剪枝
用 mins[i] 表示第 i 层最小的表面积 minv[i] 表示第 i 层最小体积,设最底层为第 n 层,枚举每一层的高和半径。
不过复杂度这样复杂度上天
所以要加上优化(剪枝)
我们先来看一下下题目中的几个细节:
当 i<M 时,要求
且
这句好就告诉我们一个事情,当我们枚举半径和高度时是可以确定上下界的,这就是剪枝一
第二个细节:
看一下这个图就会发现最下面那一层的底面积是不是就是上面的上表面积之和(也就是下图涂黑的地方)
这么看来我们只要枚举到最下层是记录一下 就不用考虑涂黑的部分了,简化了程序
再看其他的剪枝:
1.如果当前搜索到的最小表面积已经大于了已知的最小表面积直接退出
2.如果当前搜索到的体积已经超过题目限制,则退出
3.如果由体积推出来当前的表面积已经不优直接退出
总结:
1.枚举半径和高度时是可以确定上下界
2.如果当前搜索到的最小表面积已经大于了已知的最小表面积直接退出
3.如果当前搜索到的体积已经超过题目限制则退出
4.如果由体积推出来当前的表面积已经不优直接退出
#include<iostream>
#include<cmath>
using namespace std;
const int N = 24, INF = 1e9;
int n, m;
int minv[N], mins[N];
int res = INF;
//记录每层的半径和高,因为会用到上一层的高度
int R[N], H[N];
//u当前层次,v当前处理的体积和,s当前处理的面积和
void dfs(int u, int v, int s)
{
if(v + minv[u] > n) return;
if(s + mins[u] >= res) return;
if (s + 2 * (n - v) / R[u + 1] >= res) return;
if(!u)
{
if(v == n) res = s;
return;
}
//搜索顺序,先R后H,从大到小
for(int r = min(R[u + 1] - 1,(int)sqrt((n - v - minv[u - 1]) / u)); r >= u; r--)
for(int h = min(H[u + 1] - 1, (n - v - minv[u - 1]) / r / r); h >= u; h--)
{
H[u] = h, R[u] = r;
//最底层的时候需要加上r*r
int t = u == m ? r * r : 0;
dfs(u - 1, v + r * r * h, s + 2 * r * h + t);
}
}
int main()
{
cin >> n >> m;
for(int i = 1; i <= m; i++)
{
minv[i] = minv[i - 1] + i * i * i;
mins[i] = mins[i - 1] + 2 * i * i;
}
//m+1层不存在,作为哨兵,减少边界情况的判断
R[m + 1] = H[m + 1] = INF;
dfs(m, 0, 0);
if(res == INF) res = 0;
cout << res << endl;
return 0;
}
F题 了
来源:2021牛客寒假算法基础集训营3 J题加法和乘法
考察:博弈(其他题)
难度:黄题
n=1 需要特判(很重要)
如果 n 不等于 1,可以发现,如果最后一次操作是后手进行,则后手必胜。(奇数+奇数=偶数,偶数乘以任何数都等于偶数)。
否则如果初始状态有至多一个偶数,先手总有办法把局面变成全部都是奇数然后交给后手,后手至多产生一个偶数,因此给先手时局面不变。在最终时由于最多只有一个偶数,所以先手必胜。
反之,如果初始状态有至少两个偶数,无论先手怎么操作,后手还给先手的时候一定还有至少两个偶数,所以先手最后面对的局面就是两个偶数,后手必胜。
#include<bits/stdc++.h>
using namespace std;
int main(){
int n;
cin >> n;
int k;
int x = 0,y = 0;
for(int i = 1;i <= n;i++){
cin >> k;
if(k % 2){
x++;
}else{
y++;
}
}
if(n == 1&&k % 2){
cout << "kk caiji";
}else if(y > 1 || n % 2){
cout << "mz nb";
}else{
cout << "kk caiji";
}
return 0;
}
G题 吗
来源:牛客 老子的全排列呢
考察:dfs,回溯(本周考点)
难度:橙题
思路:对每一位置都找当前状态下,可以放置在当前位置的所有的数。当所有位置都放好数后再逐个释放使用的数。即dfs的回溯思想。本题也可以使用STL的next_permutation函数造全排列,但还是建议大家用dfs的做法写一写。
#include<iostream>
#include<algorithm>
#include<string.h>
#include<math.h>
using namespace std;
const int N=10;
int path[N];
bool st[N];
int n;
// 计算u->n的所经过的路径path
void dfs(int u)
{
if(u==n)//边界条件
{
for(int i=0;i<n;i++) //这里是i是从0开始,i是数组下标
printf("%d ",path[i]);
printf("\n");
return ;
}
else{
for(int i=1;i<=n;i++)//注意这里i是从1开始,因为这里是排列的1~n
{
if(!st[i]){
path[u]=i;
st[i]=true;
dfs(u+1);//回溯之后,恢复现场
path[u]=0;
st[i]=false;
}
}
}
}
int main()
{
cin >> n;
dfs(0);
return 0;
}