Part 0 前言
真是无语,赛时调了两年半都没调出来,比赛已结束就调出来了。
Part 1 思路
看到第一个子任务的 k ≤ min ( n , m ) k \le \min(n,m) k≤min(n,m) 我就想到了分情况讨论,当 k ≤ min ( n , m ) k \le \min(n,m) k≤min(n,m) 时,直接填对角线即可保证射的次数最多,当 k > min ( n , m ) k > \min(n,m) k>min(n,m) 时,我原本想的是开两个数组维护行和列的石头个数,然后每次放置石头时寻找最少石头个数的行和列,在它们的交点填入石头即可。
但是这样会 TLE 掉四个点,所以我考虑先填充对角线,在依次填充所有的点,可以证得,这个算法是正确的,如果有人不明白,可以看这个。但是当
k
=
0
k=0
k=0 的时候,要特判一下,全部输出 .
,然后 continue
。
Part 2 AC code
#include<bits/stdc++.h>
using namespace std;
char Map[2003][2003];
int line[2003],column[2003];
int main() {
int t;
scanf("%d",&t);
while(t--) {
int n,m,k;
int sum=0;
scanf("%d%d%d",&n,&m,&k);
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
Map[i][j]='.';
if(k==0){
for(int i=1;i<=n;i++) {
for(int j=1;j<=m;j++) {
printf(".");
}
printf("\n");
}
continue;
}
if(k<=min(n,m)){
for(int i=1;i<=min(n,m);i++) {
Map[i][i]='S';
sum++;
if(sum==k) break;
}
}
else if(k>min(n,m)) {
for(int i=1;i<=min(n,m);i++) {
Map[i][i]='S';
sum++;
}
bool flag=false;
for(int i=1;i<=n;i++) {
for(int j=1;j<=m;j++) {
if(Map[i][j]=='.'){
Map[i][j]='S';
sum++;
}
if(sum==k) {
flag=true;
break;
}
}
if(flag) break;
}
}
for(int i=1;i<=n;i++) {
for(int j=1;j<=m;j++) {
printf("%c",Map[i][j]);
}
printf("\n");
}
}
return 0;
}