今天与提高组的几位大佬一起打了一场比赛,发现考题竟然是原题!(于是拿了400分)
这些大佬还是比我强多了
A - Buns
这道题首先强调一点做糕点的顺序不会改变答案!
所以我们就可以按顺序来
首先做第0种的白面糕点,然后做第1种,2种……m种
第i种最多做
[
a
i
b
i
]
[\frac{a_i}{b_i}]
[biai]个,所以0,1背包跑这么多遍即可
白面糕点最多可做
[
n
c
0
]
[\frac{n}{c_0}]
[c0n]个,枚举即可
为了不要浪费,
d
p
i
dp_i
dpi表示恰好用i克面团的最大收益
所以要重头到尾再扫一遍
#include<bits/stdc++.h>
using namespace std;
int n,m,a,b,c,d,dp[1010],ans;
int main(){
cin>>n>>m>>c>>d;
for(int i=1;i<=n/c;i++)dp[i*c]=i*d;
while(m--){
cin>>a>>b>>c>>d;
for(int t=1;t<=a/b;t++){
for(int i=n;i>=c;i--){
dp[i]=max(dp[i],dp[i-c]+d);
}
}
}
for(int i=1;i<=n;i++)ans=max(ans,dp[i]);
cout<<ans;
return 0;
}
C - Petya and Spiders
这道题我用非常(奇怪)有趣的方法做了出来
别急,先来分析一下数据范围
1
<
=
n
,
m
<
=
40
,
n
∗
m
<
=
40
1<=n,m<=40,n*m<=40
1<=n,m<=40,n∗m<=40
不难发现
m
i
n
(
n
,
m
)
<
=
6
min(n,m)<=6
min(n,m)<=6
于是我就有了大胆的想法——“DFS“
第一次翻车如下
如果每一只蜘蛛dfs五个方向的话,不难发现,复杂度达到了
O
(
5
n
∗
m
)
,
n
∗
m
<
=
40
O(5^{n*m}),n*m<=40
O(5n∗m),n∗m<=40
5的40次方高达9094947017729282379150390625直接TLE
第二次成功=dfs+最优性剪枝+(我自认为的玄学优化)
由于周老师教过我正难则返的思想,既然不能直接正面枚举
n
∗
m
n*m
n∗m只蜘蛛,那就枚举蜘蛛的聚集点
由于每个聚点周围的蜘蛛都会来到这个聚点,于是时间复杂度就以常数级别降了下来(我认为的玄学所在)
具体思路
首先, s p i d e r i , j spider_{i,j} spideri,j记录 i , j i,j i,j点是否还有蜘蛛,如果有,记录当前点的坐标,然后向五个方向 f o r for for一遍(上,下,左,右和他本身)并将这五个点定为聚点,将聚点五个方向的蜘蛛聚过来,然后dfs下一层 特别提醒:注意回溯 特别提醒:注意回溯 特别提醒:注意回溯
code
#include <bits/stdc++.h>
using namespace std;
struct node {
int x, y;
};
int n, m;
int ans;
bool spider[100][100];
int dx[5] = {1, -1, 0, 0, 0};
int dy[5] = {0, 0, 1, -1, 0};
void dfs(int x) {
int xx, yy;
bool flag = 0;
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
if (spider[i][j]) {
xx = i;
yy = j;
flag = 1;//找到一个还有蜘蛛的点
}
}
if (flag) break;
}
if (!flag) {
ans = min(ans, x);//统计答案求出最少聚点数,最后(n*m)-ans即为最大空白数
return;
}
if (x + 1 >= ans) return;//最优性剪枝
for (int i = 0; i < 5; i++) {
int nx = xx + dx[i];
int ny = yy + dy[i];//聚点
if (nx < 1 || nx > n || ny < 1 || ny > m) continue;
queue<node> q;
for (int k = 0; k < 5; k++) {
if (spider[nx + dx[k]][ny + dy[k]]) {
spider[nx + dx[k]][ny + dy[k]] = 0;//聚点周围的蜘蛛全部走过来
node tmp;
tmp.x = nx + dx[k], tmp.y = ny + dy[k];
q.push(tmp);
}
}
dfs(x + 1);
while (!q.empty()) {//记得回溯!!!
spider[q.front().x][q.front().y] = 1;
q.pop();
}
}
}
int main() {
cin >> n >> m;
ans = n * m;
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
spider[i][j] = 1;
}
}
dfs(0);
cout << n * m - ans;
return 0;
}