https://vjudge.net/contest/581138
A - Humidex
模拟题
题目大意
给三个类型数字通过公式来回转化
思路
求e的对数有log函数,不懂为什么不会出精度错误,很迷,给的三个数字也没有顺序,需要多判断。
#include<cstdio>
#include<iostream>
#include<cmath>
//Sometimes weather reports give the temperature and dewpoint,
// or the temperature and humidex
/*
D 15.0 H 34.0
D 25.0 H 42.3
E
*/
using namespace std;
int main()
{
char a,b;
double a1,b1;
while(1)
{
cin>>a;
if(a=='E')
break;
cin>>a1>>b>>b1;
if(a=='T'&&b=='D'||a=='D'&&b=='T')
{
if(a=='D'&&b=='T')
swap(a1,b1);
double e=6.11*(pow(2.718281828,5417.7530*((1/273.16)-(1/(b1+273.16)))));
double h=0.5555*(e-10.0);
double humidex = a1+h;
printf("T %.1lf D %.1lf H %.1lf\n",a1,b1,humidex);
}
else if(a=='T'&&b=='H'||a=='H'&&b=='T')
{
if(a=='H'&&b=='T')
swap(a1,b1);
double dewpoint;
double h=b1-a1;
double e=h/0.5555+10.0;
double x=log(e/6.11)/5417.753;
dewpoint=1/(1/273.16-x)-273.16;
printf("T %.1lf D %.1lf H %.1lf\n",a1,dewpoint,b1);
}
else // d h
{
if(a=='H'&&b=='D')
swap(a1,b1);
double e=6.11*pow(2.718281828,5417.7530*((1/273.16)-(1/(a1+273.16))));
double h=(0.5555)*(e - 10.0);
double temperature=b1-h;
printf("T %.1lf D %.1lf H %.1lf\n",temperature,a1,b1);
}
}
}
B - Moving Tables
题目大意
两排都是房间,一排两百个房间,上面按奇数,下面按偶数编号,之后房间两两之间要搬桌子,搬桌子期间中间通道全部占用,可同步进行,搬一次10分钟,求最小时间
思路
就把中间通道编号,奇数和偶数的编号调成1-200,之后对区间进行累加,重合次数最多的就是最小时间。注意坑就是,区间不一样从小到大,l,r要判断一下大小。
#include<cstdio>
#include<iostream>
#include<cmath>
#include<cstring>
using namespace std;
int box[205];
/*
3
4
10 20
30 40
50 60
70 80
2
1 3
2 200
3
10 100
20 80
30 50
*/
int main()
{
int T;
cin>>T;
while(T--)
{
int n;
cin>>n;
memset(box,0,sizeof(box));
int maxx=0;
for(int i=1; i<=n; i++)
{
int l,r;
cin>>l>>r;
if(l%2==1)
l=l+1;
if(r%2==1)
r=r+1;
l=l/2;
r=r/2;
if(l>r)
swap(l,r);
for(int j=l; j<=r; j++)
{
box[j]++;
maxx=max(box[j],maxx);
}
}
printf("%d\n",maxx*10);
}
}
C - Counterfeit Dollar
题意
有12个硬币,现在知道其中有一个假的,已知称三次天平可以找出来假硬币,假硬币有可能轻或重,每次给三组称量结果,求出哪个是硬币,是轻是重。
思路
好丑陋的代码,不懂为啥我写的这么长,思路不太好吧,我的思路就是去暴力枚举每一个假硬币,并且枚举它是轻的假还是重的假,用box数组记录每次天平上各个位置的重量,真硬币就算重量1,假轻硬币就重量0,假重硬币就重量10,最后判断,找出来就行,模拟题,写的是真费劲,OJ还不支持string 用的char还查了一堆函数,费劲,代码能力现在下降严重。
#include<cstring>
#include<cstdio>
#include<iostream>
#include<cmath>
using namespace std;
/*
1
ABCDEF GHIJKL up
ABC DEF even
I J down
*/
int box[20];
int main()
{
int n;
cin>>n;
while(n--)
{
char a[3][15],b[3][15],c[3][15];
memset(box,0,sizeof(box));
for(int i=0; i<3; i++)
{
scanf("%s %s %s",a[i],b[i],c[i]);
strcat(a[i],b[i]);
}
for(int i=1; i<=12; i++) // 枚举每个都是假币
{
char x='A'+i-1;
// 假币轻
int flagt=0;
int pos,lenn;
char t[20];
for(int j=0; j<3; j++)
{
memset(box,0,sizeof(box));
int len=strlen(a[j]);
for(int k=0; k<len; k++)
{
if(a[j][k]!=x)
box[k]++;
if(a[j][k]==x)
{
pos=k;
lenn=len;
// t=c[j];
strcpy(t,c[j]);
}
}
int box1=0,box2=0;
for(int k=0; k<len/2; k++)
box1+=box[k];
for(int k=len/2; k<len; k++)
box2+=box[k];
if(strcmp(c[j],"even")==0&&box1==box2) flagt++;
if(strcmp(c[j],"up")==0&&box1>box2) flagt++;
if(strcmp(c[j],"down")==0&&box1<box2) flagt++;
// printf("%d %d %c %d len=%d\n",box1,box2,x,flagt,len);
}
//假币重
if(flagt!=3)
{
flagt=0;
for(int j=0; j<3; j++)
{
memset(box,0,sizeof(box));
int len=strlen(a[j]);
for(int k=0; k<len; k++)
{
if(a[j][k]!=x)
box[k]++;
if(a[j][k]==x)
{
box[k]+=10;
pos=k;
lenn=len;
// t=c[j];
strcpy(t,c[j]);
}
}
int box1=0,box2=0;
for(int k=0; k<len/2; k++)
box1+=box[k];
for(int k=len/2; k<len; k++)
box2+=box[k];
if(strcmp(c[j],"even")==0&&box1==box2) flagt++;
if(strcmp(c[j],"up")==0&&box1>box2) flagt++;
if(strcmp(c[j],"down")==0&&box1<box2) flagt++;
}
}
if(flagt==3)
{
if(pos<lenn/2)
{
if(strcmp(t,"up")==0)
printf("%c is the counterfeit coin and it is heavy.\n",x);
else
printf("%c is the counterfeit coin and it is light.\n",x);
}
else
{
if(strcmp(t,"up")==0)
printf("%c is the counterfeit coin and it is light.\n",x);
else
printf("%c is the counterfeit coin and it is heavy.\n",x);
}
break;
}
}
}
}
D - Radar Installation
题目大意
雷达部署在x轴,给出半径,陆地在任意位置,现在已知所有陆地位置,要求使用最少雷达覆盖所有陆地。
思路
以每个陆地为圆心画圆,交x轴出现线段,线段长度即为这个陆地所需要的雷达区间,对每个陆地转化为一个线段,将线段按右端点排序,之后从左往右遍历线段,每次呢取端点的最右端作为雷达,下一个线段出现左端点在雷达左右两边的情况,在左边呢就不用管,在右边呢就更新右端点为新的雷达。
这个题,输入格式好奇怪,我觉得是个错题。思路对了,照着别的代码硬改出来。为什么n=0能过?不应该n0&&d0吗?
#include<cstring>
#include<cstdio>
#include<iostream>
#include<cmath>
#include<algorithm>
using namespace std;
struct node
{
double l,r;
} a[1005];
int cmp(node a,node b)
{
return a.r<b.r;
}
int main()
{
int cnt=0;
int n;double d;
while(scanf("%d%lf",&n,&d))
{
cnt++;
if(n==0) break;
int flag=0;
for(int i=1; i<=n; i++)
{
double x,y;
scanf("%lf%lf",&x,&y);
// if(d<y||d<=0)
if(d<y||d<=0)
{
flag=1;
continue;
}
double c=sqrt(1.0*d*d-1.0*y*y);
a[i].l=(double)x-c;
a[i].r=(double)x+c;
// printf("%lf %lf\n",a[i].l,a[i].r);
}
if(flag==1)
{
printf("Case %d: -1\n",cnt);
continue;
}
sort(a+1,a+1+n,cmp);
int ans=0;
double pos=-100000000;
for(int i=1; i<=n; i++)
{
if(pos<a[i].l)
{
pos=a[i].r;
ans++;
}
}
printf("Case %d: %d\n",cnt,ans);
}
}
E - Truck History
题目大意
给n个卡车,每个卡车的编号由一个七个小写字母的字符串组成,每个卡车的编号唯一,已知一开始只有一辆卡车的编号,一个卡车可以向另一个卡车转换,代价是对应七个位置的不同字母的个数,现在要求出出现所有卡车编号出现的最小代价,最后结果取倒数。
思路
对于每一个卡车都可以当作是一个结点,做一个完全图,卡车两两转换的代价就是边权,求所有卡车出现的最小代价就是最小生成树,因为是点稠密所以选prim。
#include<cstring>
#include<cstdio>
#include<iostream>
#include<cmath>
#include<algorithm>
using namespace std;
int a[2005][2005];
char truck[2005][10];
int n;
int v[2005];
int d[2005];
void prim()
{
memset(d,0x3f,sizeof(d));
memset(v,0,sizeof(v));
d[1]=0;
for(int i=1;i<n;i++)
{
int x=0;
for(int j=1;j<=n;j++)
{
if(!v[j]&&(x==0||d[j]<d[x])) x=j;
}
v[x]=1;
for(int y=1;y<=n;y++)
if(!v[y]) d[y]=min(d[y],a[x][y]);
}
}
int main()
{
while(scanf("%d",&n)&&n!=0)
{
for(int i=1; i<=n; i++)
scanf("%s",truck[i]);
for(int i=1; i<=n; i++)
for(int j=1; j<=n; j++)
{
int cnt=0;
for(int k=0; k<7; k++)
if(truck[i][k]!=truck[j][k])
cnt++;
a[i][j]=cnt;
}
prim();
int ans=0;
for(int i=2;i<=n;i++)
ans+=d[i];
printf("The highest possible quality is 1/%d.\n",ans);
}
}
F - Wormholes
题意
给n个顶点,m个权值为正的边,w个权值为负的边,现在问图中有没有一个环为负
思路
用简单的bellman-ford做,对边进行n-1轮松弛,在没有负边的情况下,可以得到一个点到所有点的最短路径,如果第n轮还能发现更短的路径,说明存在一个环为负。
#include<cstring>
#include<cstdio>
#include<iostream>
#include<cmath>
#include<algorithm>
using namespace std;
struct node
{
int u,v,w;
}e[5500];
int dist[1005];
int tot;
void add(int u,int v,int w)
{
e[++tot].u=u;
e[tot].v=v;
e[tot].w=w;
}
int main()
{
int f;
cin>>f;
while(f--)
{
int n,m,w;
cin>>n>>m>>w;
memset(dist,0x3f,sizeof(dist));
dist[1]=0;
tot=0;
for(int i=1;i<=m;i++)
{
int x,y,z;
cin>>x>>y>>z;
add(x,y,z);
add(y,x,z);
}
for(int i=1;i<=w;i++)
{
int x,y,z;
cin>>x>>y>>z;
add(x,y,-z);
}
for(int k=1;k<=n-1;k++)
for(int i=1;i<=tot;i++)
if(dist[e[i].v]>dist[e[i].u]+e[i].w)
dist[e[i].v]=dist[e[i].u]+e[i].w;
int flag=0;
for(int i=1;i<=tot;i++)
if(dist[e[i].v]>dist[e[i].u]+e[i].w)
{
flag=1;
break;
}
if(flag) cout<<"YES"<<endl;
else cout<<"NO"<<endl;
}
}
G - Balance
题目大意
一个天平,左右可以放一些砝码,不同的位置会有不同的力矩,给定c个位置,天平中间是0,给g个砝码,砝码的重量各个不同。求一共有多少种方案使得天平平衡。
思路
dp题,设dp[i][j]表示,使用了前i个砝码,目前天平右边减去左边重量的差值为j的方案数,枚举所有砝码,枚举所有重量差值,再枚举所有位置,差值存在负数,范围为 -15 * 20 * 25 到15 * 20 * 25 ,最远力臂15* 最大砝码20* 25最多数量,范围改为 0-15000,默认7500为平衡点。之后转移方案就行。
#include<cstring>
#include<cstdio>
#include<iostream>
#include<cmath>
#include<algorithm>
using namespace std;
int dp[21][15005];
//dp[i][j]: 放了前i个物品,砝码右边减去砝码左边重量的差值为j时候的方案数
int pos[25];
int fama[25];
int main()
{
int c,g;
scanf("%d%d",&c,&g);
for(int i=1;i<=c;i++)
scanf("%d",&pos[i]);
for(int i=1;i<=g;i++)
scanf("%d",&fama[i]);
dp[0][7500]=1;
for(int i=1;i<=g;i++)
for(int j=0;j<=15000;j++)
{
for(int k=1;k<=c;k++)
if(j+fama[i]*pos[k]<=15000)
dp[i][j+fama[i]*pos[k]]+=dp[i-1][j];
}
printf("%d",dp[g][7500]);
}
H - Cow Bowling
题目大意
从顶点往下向左或向右,走到最下面,找到一条累加和最大的值。
思路
数字三角形经典题
#include<cstring>
#include<cstdio>
#include<iostream>
#include<cmath>
#include<algorithm>
using namespace std;
int dp[355][355];
int m[355][355];
int main()
{
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
for(int j=1;j<=i;j++)
scanf("%d",&m[i][j]);
}
for(int i=1;i<=n;i++)
dp[n][i]=m[n][i];
for(int i=n-1;i>=1;i--)
for(int j=1;j<=i;j++)
{
dp[i][j]=m[i][j]+max(dp[i+1][j],dp[i+1][j+1]);
}
printf("%d",dp[1][1]);
}
J - Beat the Spread!
简单题,注意非负可以为0
#include<cstring>
#include<cstdio>
#include<iostream>
#include<cmath>
#include<algorithm>
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
int a,b;
scanf("%d%d",&a,&b);
if((a+b)%2)
{
printf("impossible\n");
continue;
}
int maxx=(a+b)/2;
int minn=a-maxx;
if(maxx<0||minn<0)
{
printf("impossible\n");
continue;
}
printf("%d %d\n",maxx,minn);
}
}