2020 GDUT Rating Contest II (Div2)
A
题意:
给出若干个连通块及n个点的坐标,以及M条边表示(a,b) 属于同一连通块。
求至少框住一个连通块的最小矩形。
解题思路:
直接暴力做就好了,把连通块连起来的时候顺便记录下连通块的边界坐标。最后每个联通块都找一遍取最小值即可。
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
struct node{
int maxx,minx,maxy,miny;
}f[100005];
int fa[100005];
int fa_find(int u){
return fa[u]==u ? u :fa[u]=fa_find(fa[u]);
}
long long func(int k){
k=fa_find(k);
int dx=f[k].maxx-f[k].minx,dy=f[k].maxy-f[k].miny;
return 2LL*(dx+dy);
}
void join(int x,int y){
int fx=fa_find(x);
int fy=fa_find(y);
fa[fx]=fa[fy];
f[fy].maxx=max(f[fx].maxx,f[fy].maxx);
f[fy].maxy=max(f[fx].maxy,f[fy].maxy);
f[fy].minx=min(f[fx].minx,f[fy].minx);
f[fy].miny=min(f[fx].miny,f[fy].miny);
}
int main(){
int n,m;
scanf("%d %d",&n,&m);
int x,y;
for (int i=1;i<=n;i++){
scanf("%d %d",&x,&y);
fa[i]=i;
f[i].maxx=x;f[i].maxy=y;
f[i].minx=x;f[i].miny=y;
}
int u,v;
for (int i=1;i<=m;i++){
scanf("%d %d",&u,&v);
join(u,v);
}
long long ans=1000000000;
for (int i=1;i<=n;i++)
ans=min(ans,func(i));
printf("%lld\n",ans);
}
B Snakes
题意:
给出N个整数(1<N<=400),表示蛇的大小。
当网的大小S大于等于蛇的大小a[i]时可以捕捉这条蛇,浪费的空间为S-a[i]。
你可以在任意时机改变网的大小K次(1<=k<N)
求最少浪费多少空间。
解题思路:
直接dp,dp[i][j]表示前 i 条蛇变化了 j 次网的大小浪费的最小空间。
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<iostream>
using namespace std;
long long dp[405][405];
int pre[405],a[405];
int main(){
int n,t,maxn=0;
scanf("%d %d",&n,&t);
for (int i=1;i<=n;i++){
scanf("%d",&a[i]);
pre[i]+=pre[i-1]+a[i];
maxn=max(maxn,a[i]);
dp[i][0]=maxn*i-pre[i];
}
for(int i=1;i<=n;i++)
for (int j=1;j<=n;j++)
dp[i][j]=0x3f3f3f3f;
for (int j=1;j<=t;j++)
for (int i=j+1;i<=n;i++)
{
maxn=a[i];
for (int k=i-1;k>=j;k--)
{
maxn=max(maxn,a[k+1]);
dp[i][j]=min(dp[i][j],dp[k][j-1]+maxn*(i-k)-(pre[i]-pre[k]));
}
}
printf("%lld\n",dp[n][t]);
return 0;
}
D Left Out
题意:
给出一个N*N大小的矩阵,矩阵的每个点有两种状态,每次操作可以使得矩阵的列或者行上所有的点改变状态。
要使矩阵除了一个点以外所有的点变成同一状态。求不同状态的点的坐标,输出行指数最小的方案。如果不存在输出-1.
解题思路:
模拟,先把利用列变化把最下面那行变成同一状态,然后从第一行往下走,分别统计每一行两种状态的数目得出无法同一状态的点的数量如果这个数量小于等于一则把该行所有点(或者剩一个点)的状态变成与底行一致,判断状态不一致的点数是否为1,最后遍历一遍整个矩阵找到状态不同的点输出即可。
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
int mp[1005][1005];
int n;
void rturn(int x){
for (int i=1;i<=n;i++)
mp[i][x]^=1;
return;
}
void cturn(int x){
for (int i=1;i<=n;i++)
mp[x][i]^=1;
return;
}
int main(){
scanf("%d",&n);
char c;
for (int i=1;i<=n;i++){
getchar();
for (int j=1;j<=n;j++){
c=getchar();
if (c=='R') mp[i][j]=1;
}
}
for (int i=1;i<=n;i++)
if (mp[n][i]==0) rturn(i);
int cnt=0;
for (int i=1;i<n;i++){
int cnt0=0;
for (int j=1;j<=n;j++)
if (mp[i][j]==0) cnt0++;
if (cnt0>=n-1) cturn(i);
if (min(cnt0,n-cnt0)==1) cnt++;
}
if (cnt==1)
{
for (int i=1;i<=n;i++)
for (int j=1;j<=n;j++)
if (mp[i][j]==0)
{
printf("%d %d\n",i,j);
return 0;
}
}
else printf("-1\n");
return 0;
}
F Milk Factory
题意:
给出一个有N个点,N-1条边的有向图。求从任意一个点出发都能到达的点的编号。如果不存在这样的点则输出-1.
解题思路:
直接跑一遍Floyd,然后统计能到达这个点的所有点的数目。
如果这个数目等于n-1则输出该点坐标。
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
int mp[105][105];
int cnt[105];
int main(){
int n;
scanf("%d",&n);
int u,v;
for (int i=1;i<n;i++){
scanf("%d %d",&u,&v);
mp[u][v]=1;
}
for (int k=1;k<=n;k++)
for (int i=1;i<=n;i++)
for (int j=1;j<=n;j++)
mp[i][j]|=mp[i][k]&&mp[k][j];
for (int i=1;i<=n;i++)
for (int j=1;j<=n;j++)
if (mp[i][j]) cnt[j]++;
for (int i=1;i<=n;i++)
if (cnt[i]==n-1)
{
printf("%d\n",i);
return 0;
}
printf("-1\n");
return 0;
}
G Bucket Brigade
题意:
给出一张图,图上有障碍物,问从点B到点L最少要走多远路(只能水平或者竖直移动)
解题思路:
初始化好之后直接bfs即可。
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
const int dx[4]={0,-1,0,1};
const int dy[4]={-1,0,1,0};
struct {
int x,y,cnt;
}f[105],q[105];
int ans=0;
int mp[15][15];
bool flg;
bool check(int x,int y){
if (x==0||x==11||y==0||y==11) return false;
if (mp[x][y]==2) flg=true;
if (mp[x][y]==1) return false;
mp[x][y]=1;
return true;
}
int main(){
char c;
int x1,x2,y1,y2,cnt1=0;
for (int i=1;i<=10;i++){
for (int j=1;j<=10;j++){
c=getchar();
if (c=='B')
{
q[1].x=i;q[1].y=j;q[1].cnt=0;
mp[i][j]=1;
}
if (c=='L') mp[i][j]=2;
if (c=='R') mp[i][j]=1;
}
getchar();
}
int head=1,tail=1;
flg=false;
while (head<=tail){
for (int j=0;j<4;j++)
if (check(q[head].x+dx[j],q[head].y+dy[j]))
{
tail++;
q[tail].x=q[head].x+dx[j];
q[tail].y=q[head].y+dy[j];
q[tail].cnt=q[head].cnt+1;
}
if (flg)
{
ans+=q[head].cnt;
break;
}
head++;
}
printf("%d\n",ans);
return 0;
}
H I Would Walk 500 Miles
题意:
把n(n<7500)头牛分成k组,对于不同组的牛,牛X和牛Y会走(2019201913x+2019201949y) mod 2019201997的距离去见面,求分组后该距离的最大值
解题思路:
相当于求解2019201997-84x-48y的最大值,显然y取最大值n,x取最小k-1(1~k-1全部单独一组)。
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<iostream>
using namespace std;
int main(){
int n,k;
scanf("%d %d",&n,&k);
int ans=2019201997;
ans-=n*48;
ans-=84*(k-1);
printf("%d\n",ans);
return 0;
}