地址:http://acm.hust.edu.cn:8080/judge/contest/view.action?cid=17581#problem/A
第一题:这题求用多少块边长为a的砖,能铺满n*m的广场,不能切割。。。直接除就行,比赛时大家基本都过了
代码:
#include<cstdio>
#include<iostream>
using namespace std;
long long n,m,a,s;
int main()
{
while(cin>>n>>m>>a)
{
if(n%a)s=n/a+1;
else s=n/a;
if(m%a)s=s*(m/a+1);
else s=s*(m/a);
cout<<s<<endl;
}
return 0;
}
第二题:这题求n个人比赛的最终排名,得分相同的,最早超过该分数的人获胜,这题有很多坑,导致我错了好多次T_T
分析:假设最后答案为m。
1.一个人先獲得超m的分数,然后减到m以下,这时第二个人获得m分,然后前一个人加回m分,这样还算第一个人胜。。。
各种坑啊,然后我就记录第i时间,该时间相应的人,当时的得分,最后扫描一遍,分数最先超过m,且最终分数为m的人就是winner
代码:
#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
const int mm=1111;
char name[mm][44],str[44];
int s[mm],r1[mm],r2[mm];
int i,j,a,n,m,ms;
int find()
{
for(i=0;i<m;++i)
if(!strcmp(str,name[i]))return i;
s[m]=0;
strcpy(name[m],str);
return m++;
}
int main()
{
while(~scanf("%d",&n))
{
j=m=0;
while(n--)
{
scanf("%s%d",str,&a);
i=find();
s[i]+=a;
r1[j]=i,r2[j++]=s[i];
}
for(ms=i=0;i<m;++i)
ms=max(ms,s[i]);
i=0;
while(j--)
if(s[r1[j]]==ms&&r2[j]>=ms)i=r1[j];
puts(name[i]);
}
return 0;
}
第三题:这题就是进制转化的问题,而且只需要转化一维
分析:这题纯字母转数字大家应该都会吧,就是比如ADE=((A-A+1)*26+(D-A+1))*26+(E-A+1),关键是对于数字怎样转成字母的,这个有个小坑,不是直接%26就行的,因为会出现0,而0需要向前借一位,也就是说0代表Z,其实我也是猜的= =
代码:
#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
char s[1111],tmp[1111];
int n;
bool isnum(char c)
{
return c>='0'&&c<='9';
}
bool check()
{
for(int i=1;i<strlen(s);++i)
if(isnum(s[i-1])&&!isnum(s[i]))return 0;
return 1;
}
void change1()
{
int i=0,a=0,b=0;
while(!isnum(s[i]))
{
a=a*26+s[i]-'A'+1;
++i;
}
while(i<strlen(s))
{
b=b*10+s[i]-'0';
++i;
}
sprintf(s,"R%dC%d",b,a);
}
void decode(int a)
{
int i=0,m=0;
while(a>0)
{
tmp[m]=a%26;
a/=26;
if(!tmp[m])tmp[m]=26,--a;
++m;
}
for(i=0;i<m>>1;++i)
swap(tmp[i],tmp[m-i-1]);
for(i=0;i<m;++i)tmp[i]+='A'-1;
tmp[m]='\0';
}
void change2()
{
int i=1,a=0,b=0;
while(isnum(s[i]))
{
b=b*10+s[i]-'0';
++i;
}
++i;
while(i<strlen(s))
{
a=a*10+s[i]-'0';
++i;
}
decode(a);
sprintf(s,"%s%d",tmp,b);
}
int main()
{
while(~scanf("%d",&n))
{
while(n--)
{
scanf("%s",s);
if(check())change1();
else change2();
puts(s);
}
}
return 0;
}
第四题:这题求一条路径上的数,使得这些数相乘后后边的0的个数最少
分析:这题一看就是DP问题,但是需要数学的一点分析,当时我一看就吓到了(数学弱渣T_T),然后去做E题了
对于表格中有0的情况,答案最多为1,路径便是通过这个点的路径;或者为0;咱们先抛弃这种情况不谈,把0当作10处理
然后我们发现,后导0只能从2*5得到(10也被分解成2*5了),也就是说对于一条路径上的数都做因数分解,最后的后导0即,min(2的个数,5的个数)
那么原问题转化为求一条路径使得min(2的个数,5的个数)最小;仔细思考,我们发现可以分开求,也就是说不管5有几个的情况下,使得2最少,另一个类似
这样答案就是最少的2,或最少的5,取最小即可,这个DP很简单,就详说了
代码:
#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
const int mm=1111;
int a[mm][mm],b[mm][mm],c[mm][mm],s[mm][mm];
char p[mm][mm],out[mm*2];
int i,j,k,n,ans;
void zero()
{
for(i=1;i<=n;++i)
for(j=1;j<=n;++j)
if(!a[i][j])return;
}
void oout(int x,int y)
{
if(x==1&&y==1)return;
if(p[x][y]=='R')oout(x,y-1);
else oout(x-1,y);
out[k++]=p[x][y];
}
int main()
{
while(~scanf("%d",&n))
{
ans=1e9;
for(i=1;i<=n;++i)
for(j=1;j<=n;++j)
{
scanf("%d",&a[i][j]);
if(a[i][j])
{
b[i][j]=c[i][j]=0;
while(!(a[i][j]%2))
++b[i][j],a[i][j]>>=1;
while(!(a[i][j]%5))
++c[i][j],a[i][j]/=5;
}
else b[i][j]=c[i][j]=ans=1;
}
if(ans==1)
{
zero();
k=0;
for(j=1;j<i;++j,++k)out[k]='D';
for(j=1;j<n;++j,++k)out[k]='R';
for(;i<n;++i,++k)out[k]='D';
out[k]='\0';
}
memset(s,10,sizeof(s));
s[0][1]=s[1][0]=0;
for(i=1;i<=n;++i)
for(j=1;j<=n;++j)
if(s[i-1][j]<s[i][j-1])s[i][j]=s[i-1][j]+b[i][j],p[i][j]='D';
else s[i][j]=s[i][j-1]+b[i][j],p[i][j]='R';
if(s[n][n]<ans)ans=s[n][n],k=0,oout(n,n);
memset(s,10,sizeof(s));
s[0][1]=s[1][0]=0;
for(i=1;i<=n;++i)
for(j=1;j<=n;++j)
if(s[i-1][j]<s[i][j-1])s[i][j]=s[i-1][j]+c[i][j],p[i][j]='D';
else s[i][j]=s[i][j-1]+c[i][j],p[i][j]='R';
if(s[n][n]<ans)ans=s[n][n],k=0,oout(n,n);
printf("%d\n",ans);
puts(out);
}
return 0;
}
第五题:这题给你三个点,求以这三个点为其三个顶点的多边形,这样的多边形的最小可能面积
分析:这题一看好像没办法搞,不过仔细想想便知道以这三个点画圆,可以求出圆心,进而求出这三个点的旋转角度,还有三个点划分出的三个弧度角
然后我们可以枚举多边形是几边行(由于边数越多,越接近圆,面积也越大,所以从小开始枚举,满足就退出),n满足的条件即,2*pi/n这个为每个小块的弧度,这个弧度a刚好是三个弧度角的约数(近似值就行),这时候该多边形就是n边形,而一个小块的面积s为r*r*sin(a)/2,总面积就是n乘以s。。。
代码:
#include<cmath>
#include<cstdio>
#include<iostream>
using namespace std;
double ax,ay,bx,by,cx,cy,r,a1,a2,a3,ax1,ay1,bx1,by1,cx1,cy1,t1,t2,t3,x,y,ans;
double dis(double x1,double y1,double x2,double y2)
{
return sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));
}
bool ok(double aa)
{
int tmp;
tmp=(int)(t1/aa);
if(fabs(tmp*aa-t1)>1e-6&&fabs((tmp+1)*aa-t1)>1e-6)return 0;
tmp=(int)(t2/aa);
if(fabs(tmp*aa-t2)>1e-6&&fabs((tmp+1)*aa-t2)>1e-6)return 0;
tmp=(int)(t3/aa);
if(fabs(tmp*aa-t3)>1e-6&&fabs((tmp+1)*aa-t3)>1e-6)return 0;
return 1;
}
int main()
{
while(~scanf("%lf%lf%lf%lf%lf%lf",&ax,&ay,&bx,&by,&cx,&cy))
{
ax1=ax,ay1=ay;
bx1=bx,by1=by;
cx1=cx,cy1=cy;
a1=atan2(by-ay,bx-ax)+acos(-1.0)/2;
a2=atan2(cy-by,cx-bx)+acos(-1.0)/2;
ax=(ax+bx)/2,ay=(ay+by)/2;
bx=(cx+bx)/2,by=(cy+by)/2;
r=(sin(a2)*(ax-bx)+cos(a2)*(by-ay))/(sin(a1)*cos(a2)-sin(a2)*cos(a1));
x=ax+r*cos(a1),y=ay+r*sin(a1);
a1=atan2(ay1-y,ax1-x);
a2=atan2(by1-y,bx1-x);
a3=atan2(cy1-y,cx1-x);
if(a1<0)a1+=2*acos(-1.0);
if(a2<0)a2+=2*acos(-1.0);
if(a3<0)a3+=2*acos(-1.0);
if(a1>a2)swap(a1,a2);
if(a1>a3)swap(a1,a3);
if(a2>a3)swap(a2,a3);
t1=a2-a1,t2=a3-a2,t3=2*acos(-1.0)-a3+a1;
for(int i=3;i<1e6;++i)
{
a1=2*acos(-1.0)/i;
if(ok(a1))break;
}
r=dis(x,y,ax1,ay1);
ans=(2*acos(-1.0)/a1)*(sin(a1)*r*r/2);
printf("%.8lf\n",ans);
}
return 0;
}
第六题:好吧,我还没调出来。。。。希望有人提供题解,以后提供题解被采用也加分^_^