这场比赛开的是长沙的现场赛,感觉难度不是很高的样子。很多题目都可以开的样子,然后妥妥的开了一道神奇的搜索题,后面两道几何也都写的比较挫,玻璃那道题还处理得不好,精度不够一直WA,后来看了别人的二分写法才知道自己的写法太挫了,K题当时觉得是模板题没敢开。
队友做的,大概是有N种优惠方案,给出多次询问,注意时间
#include<cstring>
#include<string>
#include<fstream>
#include<iostream>
#include<iomanip>
#include<cstdio>
#include<cctype>
#include<algorithm>
#include<queue>
#include<map>
#include<set>
#include<vector>
#include<stack>
#include<ctime>
#include<cstdlib>
#include<functional>
#include<cmath>
using namespace std;
#define PI acos(-1.0)
#define MAXN 100100
#define eps 1e-7
#define INF 0x7FFFFFFF
#define seed 131
//#define long long ll;
#define unsigned long long ull;
#define lson l,m,rt<<1
#define rson r,m+1,rt<<1|1
long long s[MAXN],p[MAXN];
long long minm[MAXN];
int main(){
long long n, m, i, j;
long long t;
long long x,ans;
scanf("%I64d",&t);
while(t--){
scanf("%I64d%I64d",&n,&m);
for(i=0;i<n;i++){
scanf("%I64d%I64d",&s[i],&p[i]);
}
minm[n-1] = s[n-1] * p[n-1];
for(i=n-2;i>=0;i--){
long long tt = s[i] * p[i];
minm[i] = min(tt,minm[i+1]);
}
for(i=0;i<m;i++){
scanf("%I64d",&x);
int pp = upper_bound(s,s+n,x)-s;
pp--;
if(pp==n-1){
ans = x * p[n-1];
}
else
ans = min(minm[pp+1],x*p[pp]);
printf("%I64d\n",ans);
}
}
return 0;
}
C题 几何
#include <math.h>
#include <stdio.h>
#define eps 1e-8
struct point{double x,y;};
double max(double a,double b)
{
if(a>b) return a;
else return b;
}
double xmult(point p1,point p2,point p0){
return (p1.x-p0.x)*(p2.y-p0.y)-(p2.x-p0.x)*(p1.y-p0.y);
}
double distance(point p1,point p2){
return sqrt((p1.x-p2.x)*(p1.x-p2.x)+(p1.y-p2.y)*(p1.y-p2.y));
}
double disptoline(point p,point l1,point l2){
return fabs(xmult(p,l1,l2))/distance(l1,l2);
}
point intersection(point u1,point u2,point v1,point v2){
point ret=u1;
double t=((u1.x-v1.x)*(v1.y-v2.y)-(u1.y-v1.y)*(v1.x-v2.x))
/((u1.x-u2.x)*(v1.y-v2.y)-(u1.y-u2.y)*(v1.x-v2.x));
ret.x+=(u2.x-u1.x)*t;
ret.y+=(u2.y-u1.y)*t;
return ret;
}
//判直线和圆相交,包括相切
int intersect_line_circle(point c,double r,point l1,point l2){
/*printf("%lf\n",r+eps);
printf("%lf\n",disptoline(c,l1,l2)); //dayu dengyu*/
if(disptoline(c,l1,l2)-r>-eps) return 0;
else return 1;
}
//判线段和圆相交,包括端点和相切
int intersect_seg_circle(point c,double r,point l1,point l2){
double t1=distance(c,l1)-r,t2=distance(c,l2)-r;
point t=c;
if (t1<eps||t2<eps)
return t1>-eps||t2>-eps;
t.x+=l1.y-l2.y;
t.y+=l2.x-l1.x;
return xmult(l1,c,t)*xmult(l2,c,t)<eps&&disptoline(c,l1,l2)-r<eps;
}
//判圆和圆相交,包括相切
int intersect_circle_circle(point c1,double r1,point c2,double r2){
return distance(c1,c2)<r1+r2+eps&&distance(c1,c2)>fabs(r1-r2)-eps;
}
//计算圆上到点p最近点,如p与圆心重合,返回p本身
point dot_to_circle(point c,double r,point p){
point u,v;
if (distance(p,c)<eps)
return p;
u.x=c.x+r*fabs(c.x-p.x)/distance(c,p);
u.y=c.y+r*fabs(c.y-p.y)/distance(c,p)*((c.x-p.x)*(c.y-p.y)<0?-1:1);
v.x=c.x-r*fabs(c.x-p.x)/distance(c,p);
v.y=c.y-r*fabs(c.y-p.y)/distance(c,p)*((c.x-p.x)*(c.y-p.y)<0?-1:1);
return distance(u,p)<distance(v,p)?u:v;
}
//计算直线与圆的交点,保证直线与圆有交点
//计算线段与圆的交点可用这个函数后判点是否在线段上
void intersection_line_circle(point c,double r,point l1,point l2,point& p1,point& p2){
point p=c;
double t;
p.x+=l1.y-l2.y;
p.y+=l2.x-l1.x;
p=intersection(p,c,l1,l2);
t=sqrt(r*r-distance(p,c)*distance(p,c))/distance(l1,l2);
p1.x=p.x+(l2.x-l1.x)*t;
p1.y=p.y+(l2.y-l1.y)*t;
p2.x=p.x-(l2.x-l1.x)*t;
p2.y=p.y-(l2.y-l1.y)*t;
}
//计算圆与圆的交点,保证圆与圆有交点,圆心不重合
void intersection_circle_circle(point c1,double r1,point c2,double r2,point& p1,point& p2){
point u,v;
double t;
t=(1+(r1*r1-r2*r2)/distance(c1,c2)/distance(c1,c2))/2;
u.x=c1.x+(c2.x-c1.x)*t;
u.y=c1.y+(c2.y-c1.y)*t;
v.x=u.x+c1.y-c2.y;
v.y=u.y-c1.x+c2.x;
intersection_line_circle(c1,r1,u,v,p1,p2);
}
int main ()
{
double Rm,R,r,x,y,vx,vy;
while(~scanf("%lf %lf %lf %lf %lf %lf %lf",&Rm,&R,&r,&x,&y,&vx,&vy))
{
point O; O.x=0; O.y=0;
point P; P.x=x; P.y=y;
point Pd; Pd.x=x+vx/10; Pd.y=y+vy/10;
point p1,p2,p3,p4;
/*printf("%lf %lf\n",P.x,P.y);
printf("%lf %lf\n",Pd.x,Pd.y);*/
if(distance(O,P)<distance(O,Pd)) {printf("0\n");continue;}
if(intersect_line_circle(O,R+r,P,Pd)==0) {printf("0\n");continue;} //与大圆相离
else if(intersect_line_circle(O,Rm+r,P,Pd)==0) //与小圆相离
{
intersection_line_circle(O,R+r,P,Pd,p1,p2);
/*printf("%lf %lf\n",p1.x,p1.y);
printf("%lf %lf\n",p2.x,p2.y);*/
if(p1.x!=p2.x)
printf("%.3lf\n",fabs((p1.x-p2.x)/vx));
else
printf("%.3lf\n",fabs((p1.y-p2.y)/vy));
}
else
{
intersection_line_circle(O,R +r,P,Pd,p1,p2);
intersection_line_circle(O,Rm+r,P,Pd,p3,p4);
/*printf("%lf %lf\n",p1.x,p1.y);
printf("%lf %lf\n",p2.x,p2.y);
printf("%lf %lf\n",p3.x,p3.y);
printf("%lf %lf\n",p4.x,p4.y);*/
if(p1.x!=p2.x)
printf("%.3lf\n",2*fabs((max(p1.x,p2.x)-max(p3.x,p4.x))/vx));
else
printf("%.3lf\n",2*fabs((max(p1.y,p2.y)-max(p3.y,p4.y))/vy));
}
//else printf("大相交\n");
}
}
/*
5 20 1 0 100 0 -1
5 20 1 30 15 -1 0
5 20 1 0 21 1 0
*/
J题DP dp[i][j],i表示打到第几个AI队伍,j表示次使用的是哪种组合的队伍,每次判断如果dp[i][j]大于dp[i][ai[i]]的话更新,最后找一遍最大值。很简单的DP写的很挫。。。。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <cstdlib>
#define eps 1e-8
using namespace std;
const int maxn=11000;
int n,m;
double a[11000][200];
int b[11100];
double dp[11000][200];
int dis(int n)
{
int sum;
sum=n*(n-1)*(n-2);
sum/=6;
return sum;
}
int main()
{
while(scanf("%d",&n)!=EOF)
{
n=dis(n);
memset(dp,0,sizeof(dp));
for(int i=0;i<n;i++)
{
for(int j=0;j<n;j++)
{
scanf("%lf",&a[i][j]);
}
}
scanf("%d",&m);
for(int i=1;i<=m;i++)
{
scanf("%d",&b[i]);
}
for(int i=0;i<n;i++)
{
dp[0][i]=1.0;
}
//cout<<dp[0][3]<<endl;
for(int i=1;i<=m;i++)
{
for(int j=0;j<n;j++)
{
dp[i][j]=dp[i-1][j]*a[j][b[i]];
//dp[i][b[i]]=max(dp[i][b[i]],dp[i][j]);
}
for(int j=0;j<n;j++)
{
//dp[i][b[i]]=max(dp[i][b[i]],dp[i][j]);
if(dp[i][j]-dp[i][b[i]]>eps)
{
dp[i][b[i]]=dp[i][j];
}
}
//printf("%.6lf\n",sum1);
}
double sum=-1;
for(int i=0;i<n;i++)
{
if(sum<dp[m][i])
{
sum=dp[m][i];
}
}
printf("%.6lf\n",sum);
//cout<<p<<endl;
}
return 0;
}
H题 奇葩题目,题意难懂,但实际上是一道很水的数学题,用正N边形的玻璃围住一个圆,就是找内切圆的半径,但是比赛过程中我卡精度没过,实际上可能是写法太挫太暴力的原因吧,改成二分过了
注意S是玻璃最小面积 H/L是每块玻璃的高,所以边长和边数的关系就可以确定了,二分一下就可以得出结果。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <queue>
#include <cstdlib>
#include <iomanip>
#include <algorithm>
using namespace std;
const double pi=acos(-1.0);
double getlen(int n,double r)
{
return 2.0*r*tan(pi/n);
}
int main()
{
int R,r,H,S;
int L;
while(scanf("%d%d%d%d%d",&R,&r,&H,&L,&S)!=EOF)
{
double h=(H*1.0)/L;
double ans=0;
int k=100000;
for(int i=L;i>=1;i--)
{
double rr=1.0*(R-r)/L*(i-1)+r;
int low=3;
int high=k;
int mid;
double s;
int num;
while(low<=high)
{
mid=(low+high)>>1;
double temp=getlen(mid,rr)*h;//单块玻璃面积
if(temp-S>1e-8)//面积不能小于S
{
s=temp;
num=mid;//边数
low=mid+1;
}
else
{
high=mid-1;
}
}
ans+=num*s;
//k=num;
}
printf("%.3lf\n",ans);
}
return 0;
}
K题:看到是魔方题目,以为是模板题,比赛的时候没敢做,赛后读发现不是很难的题目
给了一个2*2的魔方..每步操作可以将任意一面翻转90度..现在问在N(<=7)步内..最多能翻出几面相同的,因为最多只旋转7次,所以我们可以直接暴力搜索求最大,六个面顺时针逆时针一遍一共12中转法,不过因为只有2*2*2,所以对于相对的两个面,一个面顺时针旋转等价于另一个面逆时针转,所以可以缩减为6种旋转。只要把六种旋转的面的对应关系搞清楚就行了.
打表写法
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <queue>
#include <algorithm>
#include <iomanip>
#include <cstdlib>
using namespace std;
int MS[6][24]={ {6,1,12,3,5,11,16,7,8,9,4,10,18,13,14,15,20,17,22,19,0,21,2,23},
{20,1,22,3,10,4,0,7,8,9,11,5,2,13,14,15,6,17,12,19,16,21,18,23},
{1,3,0,2,23,22,4,5,6,7,10,11,12,13,14,15,16,17,18,19,20,21,9,8},
{2,0,3,1,6,7,8,9,23,22,10,11,12,13,14,15,16,17,18,19,20,21,5,4},
{0,1,8,14,4,3,7,13,17,9,10,2,6,12,16,15,5,11,18,19,20,21,22,23},
{0,1,11,5,4,16,12,6,2,9,10,17,13,7,3,15,14,8,18,19,20,21,22,23}
};
int ans;
void update(int *h)
{
int sum=0;
if (h[0]==h[1] && h[1]==h[2] && h[2]==h[3]) sum++;
if (h[4]==h[5] && h[5]==h[10] && h[10]==h[11]) sum++;
if (h[6]==h[7] && h[7]==h[12] && h[12]==h[13]) sum++;
if (h[8]==h[9] && h[9]==h[14] && h[14]==h[15]) sum++;
if (h[16]==h[17] && h[17]==h[18] && h[18]==h[19]) sum++;
if (h[20]==h[21] && h[21]==h[22] && h[22]==h[23]) sum++;
ans=max(ans,sum);
}
void dfs(int n,int *h)
{
update(h);
if(!n)
{
return ;
}
int p[24];
for(int k=0;k<6;k++)
{
for(int i=0;i<24;i++)
{
p[i]=h[MS[k][i]];
}
dfs(n-1,p);
}
return ;
}
int main()
{
int n;
int h[24];
while(scanf("%d",&n)!=EOF)
{
for(int i=0;i<24;i++)
{
scanf("%d",&h[i]);
}
ans=0;
dfs(n,h);
printf("%d\n",ans);
}
return 0;
}