【JZOJ 4783】 Osu

58 篇文章 0 订阅
17 篇文章 0 订阅

Description

这里写图片描述
这里写图片描述

Analysis

二分模型很显然,但是具体怎么二分
%%%CTY实数二分碾过
其实正解是把两两点对距离排序在这个数组里二分,这样个数是O(n^2)的。
判定的话可以用一个简单的n^2dp解决
这样大体框架就没了,但是此题巨猥琐卡常数
所以呢,卡常+一堆优化

Code

#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#define fo(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
typedef double db;
const int N=2010,M=N*N;
int n,m,k,f[N],g[N];
char ch;
struct node
{
    int t,x,y;
}a[N];
struct lyd
{
    int a,b,c;
    db s;
}dis[M],cty;
int read()
{
    int t=0,p=1;
    for(ch=getchar();ch<'0' || ch>'9';ch=getchar())
        if(ch=='-') p=-1;
    for(;'0'<=ch && ch<='9';ch=getchar()) t=t*10+ch-'0';
    return t*p;
}
int sqr(int x){return x*x;}
int gcd(int x,int y)
{
    if(x%y==0) return y;
    else return gcd(y,x%y);
}
db dist(node a,node b)
{
    return sqrt(sqr(a.x-b.x)+sqr(a.y-b.y));
}
void getdis(node a,node b)
{
    int d=sqr(a.x-b.x)+sqr(a.y-b.y),t=b.t-a.t;
    dis[++m].s=sqrt(d)/t,dis[m].a=1,dis[m].b=d,dis[m].c=t;
}
bool biger(db a,db b)
{
    return (a-b<=1e-9 && b-a<=1e-9) || a>=b;
}
bool check(db s)
{
    memset(f,0,sizeof(f));
    int mx=0;
    fo(i,1,n)
    {
        g[i]=g[i-1];
        for(int j=i-1;j>=0;j--)
        {
            if(biger(s*(a[i].t-a[j].t),dist(a[j],a[i])))
                if(f[j]+1>f[i]) f[i]=f[j]+1;
            if(f[i]>g[j]+1) break;
        }
        if(f[i]>mx) mx=f[i];
        if(f[i]>g[i]) g[i]=f[i];
    }
    if(mx>=k) return 1;
    return 0;
}
void qsort(int i,int j)
{
    int l=i,r=j;
    db mid=dis[(i+j)>>1].s;
    do
    {
        while(dis[i].s<mid) i++;
        while(dis[j].s>mid) j--;
        if(i<=j)
        {
            cty=dis[i];
            dis[i]=dis[j];
            dis[j]=cty;
            i++,j--;
        }
    }
    while(i<=j);
    if(i<r) qsort(i,r);
    if(l<j) qsort(l,j);
}
int main()
{
    n=read(),k=read();
    fo(i,1,n) a[i].t=read(),a[i].x=read(),a[i].y=read();
    fo(i,1,n-1)
        fo(j,i+1,n) getdis(a[i],a[j]);
    qsort(1,m);
    int l=1,r=m,mid;
    while(l<r)
    {
        mid=(l+r)>>1;
        if(check(dis[mid].s)) r=mid;
        else l=mid+1;
    }
    for(int i=2;i*i<=dis[l].b;i++)
        while(dis[l].b%(i*i)==0) dis[l].a*=i,dis[l].b/=i*i;
    int t=gcd(dis[l].a,dis[l].c);
    dis[l].a/=t,dis[l].c/=t;
    printf("%d %d %d",dis[l].a,dis[l].b,dis[l].c);
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值