前言
下午去东农校赛之后晚上来打的这场div2,本来就很困这场还偏偏在12.05开始,但是顶着之前一场不落的flag还是打了下来,开场很小心的写A,B,写了好久之后发现交完AB排名竟如此靠前,之后去开C,感觉不太容易,这是刷一下榜发现学弟只过D分数比我还高,于是选择去看D,看懂题意后发现是个水题,交上去1A,rank60多,上紫稳了。之后噩梦就开始了,一阵阵的502预示着这场将会unrated,最后果不其然,unrated,就这样中国玩家玩到2.30,等来unrated,虽然心情不好,但是题解还是要补的。O(∩_∩)O
A. Kitchen Utensils
题意
给你n个剩余餐具,共有k个人,之前每个人的餐具的套数都是相同的,每套餐具由几个不同的餐具,现在的n个餐具是被偷之后剩下的,问最少被偷走多少餐具。
做法
一套餐具肯定最少包含所有种类的餐具,之后看一个人最少几套餐具就可以了。
代码
#include<iostream>
#include<stdio.h>
#include<algorithm>
using namespace std;
const int maxn = 1e5+5;
int a[maxn];
int num[maxn];
int main()
{
int n,k,x;
scanf("%d%d",&n,&k);
for(int i=1;i<=n;i++)
{
scanf("%d",&x);
num[x]++;
}
int ans=0;
int sum=0;
for(int i=1;i<=100;i++)
{
if(num[i]>=1) sum++;
int tmp=(num[i]/k)+(num[i]%k!=0);
ans=max(ans,tmp);//tmp为一个人最少可能的餐具数
}
printf("%d\n",sum*k*ans-n);
return 0;
}
B. Personalized Cup
题意
给你一片文章,让你把每个字符放在一个ab的网格中,每一个位置可以是或者字符,要求为行数不超过5,列数不超过20,每相邻两行之间的*数量不能超过1.求满足条件的矩阵中行数最少的,行数相同取列最少的
做法
由于最多五行,那么只要枚举行数,判断是否满足条件即可,满足即跳出。
坑点
要注意每行最多放一个*,因为只有最后多余的那列可能会出现空
细节比较多,实现要小心
代码
#include<iostream>
#include<stdio.h>
#include<algorithm>
#include<string.h>
using namespace std;
const int maxn = 105;
char str[maxn];
char pic[maxn][maxn];
int main()
{
scanf("%s",str);
int len=strlen(str);
int flag=1;
for(int i=1;i<=5;i++)
{
if((len%i)<=i&&(len/i+(len%i!=0))<=20)
{
flag=i;
break;
}
}
int tmp=len/flag+(len%flag!=0);
int yu=tmp*flag-len;
int cnt=0;
for(int i=1;i<=yu;i++)//先将带星号的行填上
{
for(int k=1;k<=tmp-1;k++)
{
pic[i][k]=str[cnt++];
}
pic[i][tmp]='*';
}
for(int i=yu+1;i<=flag;i++)//填上不带星号的行
{
for(int k=1;k<=tmp;k++)
{
pic[i][k]=str[cnt++];
}
}
printf("%d %d\n",flag,tmp);
for(int i=1;i<=flag;i++)
{
for(int j=1;j<=tmp;j++)
{
printf("%c",pic[i][j]);
}
printf("\n");
}
return 0;
}
C. Playing Piano
题意
给你一个a数组,让你按照规则构造b数组
规则如下
如果
a
i
<
a
i
+
1
a_i<a_{i+1}
ai<ai+1那么
b
i
<
b
i
+
1
b_i<b_{i+1}
bi<bi+1
如果
a
i
>
a
i
+
1
a_i>a_{i+1}
ai>ai+1那么
b
i
>
b
i
+
1
b_i>b_{i+1}
bi>bi+1
如果
a
i
=
a
i
+
1
a_i=a_{i+1}
ai=ai+1那么
b
i
!
=
b
i
+
1
b_i!=b_{i+1}
bi!=bi+1
给出b数组或者输出-1表示b数组不存在。
做法
考虑一下会发现只有两种情况会出现-1
第一种:连续上升/下降的个数>=6个
第二种:连续五个上升/下降,连续五个下降/上升
先用枚举的方法处理掉-1的情况
不是-1的情况一定是有很多解的,直接爆搜61ms就过掉了。
目前不清楚能不能卡掉爆搜。
代码
#include<iostream>
#include<stdio.h>
#include<algorithm>
#include<string.h>
using namespace std;
const int maxn = 1e5+5;
int a[maxn];
int b[maxn];
int n,ok;
void dfs(int pos)
{
if(ok==1) return ;
if(pos==1)
{
for(int i=1;i<=5;i++)
{
b[pos]=i;
dfs(pos+1);
if(ok==1) return;
}
}
else if(pos==n+1)
{
ok=1;
return ;
}
else
{
if(a[pos]==a[pos-1])
{
for(int i=1;i<=5;i++)
{
if(b[pos-1]!=i)
{
b[pos]=i;
dfs(pos+1);
if(ok) return ;
}
}
}
else if(a[pos]<a[pos-1])
{
for(int i=b[pos-1]-1;i>=1;i--)
{
b[pos]=i;
dfs(pos+1);
if(ok) return ;
}
}
else
{
for(int i=b[pos-1]+1;i<=5;i++)
{
b[pos]=i;
dfs(pos+1);
if(ok) return ;
}
}
}
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
}
if(n==1)
{
printf("1\n");
return 0;
}
if(n==2)
{
if(a[1]<=a[2]) printf("1 2\n");
else if(a[1]>a[2]) printf("2 1\n");
return 0;
}
for(int i=1;i<=n-5;i++)//判断1 2 3 4 5 6
{
int flag=0;
for(int j=i;j<=i+4;j++)
{
if(a[j]>=a[j+1]) flag=1;
}
if(flag==0)
{
printf("-1\n");
return 0;
}
}
for(int i=1;i<=n-5;i++)//判断6 5 4 3 2 1
{
int flag=0;
for(int j=i;j<=i+4;j++)
{
if(a[j]<=a[j+1]) flag=1;
}
if(flag==0)
{
printf("-1\n");
return 0;
}
}
for(int i=1;i<=n-9;i++)//判断1 2 3 4 5 5 4 3 2 1
{
int flag=0;
for(int j=i;j<=i+3;j++)
{
if(a[j]>=a[j+1]) flag=1;
}
if(a[i+4]!=a[i+5]) flag=1;
for(int j=i+5;j<=i+8;j++)
{
if(a[j]<=a[j+1]) flag=1;
}
if(flag==0)
{
if(flag==0)
{
printf("-1\n");
return 0;
}
}
}
for(int i=1;i<=n-9;i++)//判断5 4 3 2 1 1 2 3 4 5
{
int flag=0;
for(int j=i;j<=i+3;j++)
{
if(a[j]<=a[j+1]) flag=1;
}
if(a[i+4]!=a[i+5]) flag=1;
for(int j=i+5;j<=i+8;j++)
{
if(a[j]>=a[j+1]) flag=1;
}
if(flag==0)
{
if(flag==0)
{
printf("-1\n");
return 0;
}
}
}
dfs(1);
for(int i=1;i<=n;i++) printf("%d ",b[i]);
return 0;
}
D. Barcelonian Distance
题意
给你一条二维平面上的直线,给你两个点,问从A点走到B点的最短路径
点只能在给定直线和与坐标轴平行的直线上行走。
做法
如果不经过直线,一定直接是曼哈顿距离
如果经过直线,一定是A沿直线走到直线上最优,从直线上延直线走到B最优
而从A直接走到给定直线有两种走法,从给定直线走到B有两种走法
所以只要判断上述5种走法的最小值即可。
坑点
给定直线斜率为0时注意要特判,斜率为0或者inf,那么就是曼哈顿距离
代码
#include<iostream>
#include<math.h>
#include<stdio.h>
#include<algorithm>
using namespace std;
typedef long long ll;
const int maxn = 1e5+5;
double dis(double a,double b,double c,double d)
{
return sqrt((a-c)*(a-c)+(b-d)*(b-d));
}
int main()
{
ll a,b,c,x_1,y_1,x_2,y_2;
scanf("%lld%lld%lld",&a,&b,&c);
scanf("%lld%lld%lld%lld",&x_1,&y_1,&x_2,&y_2);
double ans,ans1,xx1,yy1,xx2,yy2;
//曼哈顿距离
ans=1.0*(abs(x_2-x_1)+abs(y_2-y_1));
//x 1 y 1
ans1=0;
xx1=1.0*x_1;
yy1=-1.0*(1.0*a*x_1+c)*(1.0/b);
xx2=1.0*x_2;
yy2=-1.0*(1.0*a*x_2+c)*(1.0/b);
ans1+=fabs(yy1-y_1)+fabs(yy2-y_2);
ans1+=dis(xx1,yy1,xx2,yy2);
ans=min(ans,ans1);
//x 1 y 0
ans1=0;
xx1=1.0*x_1;
yy1=-1.0*(1.0*a*x_1+c)*(1.0/b);
xx2=-1.0*(1.0*b*y_2+c)*(1.0/a);
yy2=1.0*y_2;
ans1+=fabs(yy1-y_1)+fabs(xx2-x_2);
ans1+=dis(xx1,yy1,xx2,yy2);
ans=min(ans,ans1);
//x 0 y 0
ans1=0;
xx1=-1.0*(1.0*b*y_1+c)*(1.0/a);
yy1=1.0*y_1;
xx2=-1.0*(1.0*b*y_2+c)*(1.0/a);
yy2=1.0*y_2;
ans1+=fabs(xx1-x_1)+fabs(xx2-x_2);
ans1+=dis(xx1,yy1,xx2,yy2);
ans=min(ans,ans1);
//x 0 y 1
ans1=0;
xx1=-1.0*(1.0*b*y_1+c)*(1.0/a);
yy1=1.0*y_1;
xx2=1.0*x_2;
yy2=-1.0*(1.0*a*x_2+c)*(1.0/b);
ans1+=fabs(xx1-x_1)+fabs(yy2-y_2);
ans1+=dis(xx1,yy1,xx2,yy2);
ans=min(ans,ans1);
printf("%.10f\n",ans);
return 0;
}