第三周组队训练赛-长沙现场赛解题报告

47 篇文章 0 订阅
33 篇文章 2 订阅

这场比赛开的是长沙的现场赛,感觉难度不是很高的样子。很多题目都可以开的样子,然后妥妥的开了一道神奇的搜索题,后面两道几何也都写的比较挫,玻璃那道题还处理得不好,精度不够一直WA,后来看了别人的二分写法才知道自己的写法太挫了,K题当时觉得是模板题没敢开。

第一题:Alice's Print Service

队友做的,大概是有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;
}





  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值