A. Prison Break
题意:
有一个n*m的监狱,每一个格子有一个犯人,坐标为( r , c )的格子有一条逃生通道,犯人每一秒可以向相邻的且有人的一个格子移动,移动方向为上下左右,问所有犯人到达逃生通道最久需要多少秒。
in put:代表3种情况,m,n,r,c
3
10 10 1 1
3 5 2 4
10 2 5 1
out put:
18
4
6
注意不可以斜着走,所以只需要考虑四个角的犯人用的时间最多的即可。
而这四个角都是(r,c)到相邻两条边的距离,所以只需要找到(r,c)到两条边的最大值即可
#include<bits/stdc++.h>
using namespace std;
int main(){
int t,a,b,c,d;
scanf("%d",&t);
while (t--){
int m,n;
scanf("%d%d%d%d",&a,&b,&c,&d);
m = max(a - c, c-1);
n = max(b - d, d-1);
printf("%d\n",m+n);
}
return 0;
}
B - Repainting Street
题意:
有n个房子,1-n排成一列,每个房子有自己初始颜色ci。画家每次可以画连续的k个房子,可以画成任意颜色,或者不变。问最少画几次可以使所有的房子都变成一样的颜色。
颜色只有100种,1e5个房子,直接暴力跑,枚举每种颜色就可以
#include<bits/stdc++.h>
using namespace std;
int a[100006] ,b[106];
int main(){
int t,n,k,ans,sum;
scanf("%d",&t);
while (t--){
ans = 0x7fffffff;
scanf("%d%d",&n,&k);
for (int i = 0; i < n; i++) {
scanf("%d",&a[i]);
b[a[i]] = 1;
}
for (int i = 1; i < 101; ++i) {
sum = 0;
if(b[i]){
for (int j = 0; j < n; j++) {
if(a[j] != i) sum++,j+=(k-1);
}
ans = min(ans,sum);
}
}
printf("%d\n",ans);
}
return 0;
}
C - Bouncing Ball:
题意:
n个平台,平台标记为1时,可以使小球弹起来,小球必须从第p个位置开始,而且每次都会向右弹k个单位,标记为0的不可以弹小球,你可以花费x标记为1,也可以删除前几个单位,每个单位花费y,问最少花费多少使得小球能够弹出平台外
因为每k次一个轮回,i和i+k是相关的,所以利用后缀和求出dp数组,然后对每一种可以删除的数量进行遍历,找到最小值
用dp数组记录,从后向前遍历。
dp[i]表示从i开始弹球(i前的删除),改变标记所需要的花费
#include <bits/stdc++.h>
using namespace std;
const int inf = 0x7fffffff;
char s[100006];
int dp[100006];
signed main() {
int t,x,y,n,p,k,sum;
scanf("%d",&t);
while (t--){
memset(dp,0,sizeof(dp));
scanf("%d%d%d",&n,&p,&k);
scanf("%s",s+1);
scanf("%d%d",&x,&y);
for (int i = n; i > 0; --i) {
if(n - i >= k) dp[i] = dp[i+k];//每k个一个轮回
if(s[i] == '0') dp[i]+=x;
}
//dp数组为从后向前遍历的,
//表示从i开始弹球(i前的删除),所需要的花费
sum = inf;
for (int i = p; i <= n; ++i) {
sum = min(sum, dp[i] + y*(i-p));
}
printf("%d\n",sum);
}
return 0;
}