JZOJ 4783. Osu

Problem

Description

这里写图片描述

Input

这里写图片描述

Output

这里写图片描述

Sample Input

4 2
1 2 2
2 0 2
3 0 0
4 2 0

Sample Output

1 2 1

Hint

圆圈只在出现的时刻有效。即:时刻t_i时鼠标位置恰好在(x_i,y_i)才能得分。
Kaguya所做的工作就是在这些时刻间移动鼠标。
对于样例:选择点击第2、4个圆圈。
时间[0,2]内,鼠标从(0,0)移动到(0,2),速度为1,并在时刻2得分。
时间[2,4]内,鼠标从(0,2)移动到(2,0),速度为sqrt(2),并在时刻4得分。
因此答案为sqrt(2), a=1 b=2 c=1

Data Constraint

这里写图片描述

Solution

我们发现题目要求“最大值最小”,所以我们要想到二分。
然后通过DP算路径(路径用一个数组存),然后找最大值就行了。
DP时间复杂度:O(n2)
其实求a,b,c没有想象中的这么难。
我们将b的根号拆开,然后将b中质因数x的指数为2n的统统去掉,然后a=axn
然后a与c再约分就行了。

Code

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring> 
#define N 2010
#define fo(i,a,b) for(i=a;i<=b;i++)
#define LF double
using namespace std;
LF dis[N][N],l,r,mid,ans,t[N],x[N],y[N];
int a,b,c,d,n,i,j,k,m,A1,A2,f[N],pred[N];
int gcd(int x,int y)
{
    if (y==0) return x;else return gcd(y,x%y);
}
int main()
{
    scanf("%d%d",&n,&k);
    fo(i,1,n) scanf("%lf%lf%lf",&t[i],&x[i],&y[i]);
    fo(i,0,n-1)
        fo(j,i+1,n)
            dis[i][j]=sqrt((x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j]))/(t[j]-t[i]);
    l=0;
    r=100000000;
    while (r-l>0.001)
    {
        bool p=0;
        mid=(l+r)/2;
        memset(f,0,sizeof(f));
        ans=0;
        fo(i,0,n)
        {
            fo(j,0,i-1)
                if (dis[j][i]<=mid && f[j]+1>f[i])
                {
                    f[i]=f[j]+1;
                    pred[i]=j;
                }
            if (f[i]==k)
            {
                for (m=i;m;m=pred[m])
                {
                    if (dis[pred[m]][m]>ans)
                    {
                        A1=pred[m];
                        A2=m;
                        ans=dis[pred[m]][m];
                    }
                }
                p=1;
                break;
            }
        }
        if (p) r=mid;else l=mid;
    }
    a=1;
    b=(x[A1]-x[A2])*(x[A1]-x[A2])+(y[A1]-y[A2])*(y[A1]-y[A2]);
    c=t[A2]-t[A1];
    fo(i,2,sqrt(b))
        while (b%(i*i)==0)
        {
            a=a*i;
            b=b/(i*i);
        }
    d=gcd(a,c);
    a/=d;c/=d;
    printf("%d %d %d",a,b,c);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值