【NOIP模拟】Osu

来源:互联网 发布:手机淘宝刷到单流程图 编辑:程序博客网 时间:2024/06/08 19:23

Solution

这里写图片描述

Description

一开始没有看懂题.
后来看懂题了,发现这是一道水题。
首先,把两两点之间的值求出来,排一个序,然后在这个序列上二分。
二分出一个值x,表示DP时候的两两点的值不能超过这个x。
设f[i]表示最后一个走到i的最大积分。
那么如果g[i][j]<=x&&f[i]>f[j]+1那么f[i]就可以转移。
但是很容易被卡常,本来我的DP是打max的,然后改成直接判断就A了。

Code

#include<iostream>#include<cstdio>#include<cmath>#include<algorithm>#include<cstring>#define fo(i,a,b) for(i=a;i<=b;i++)#define fod(i,a,b) for(i=a;i>=b;i--)using namespace std;const int maxn=2007;int i,j,k,l,n,m,r,mid;int f[maxn];int x[maxn],y[maxn],t[maxn];int ans1,ans2,ans3,num;double o,ans,pan,g[maxn][maxn];struct node{    double z;    int a;}a[maxn*maxn];double ju(int x,int y,int xx,int yy){    return (xx-x)*(xx-x)+(yy-y)*(yy-y);}int gcd(int x,int y){    return(!y)? x:gcd(y,x%y);}bool cmp(node x,node y){    return x.z<y.z;}int main(){    scanf("%d%d",&n,&m);    fo(i,1,n){        scanf("%d%d%d",&t[i],&x[i],&y[i]);    }    fo(i,1,n){        fo(j,0,i-1){            if(i==j)continue;            g[i][j]=a[++num].z=sqrt(ju(x[i],y[i],x[j],y[j]))/(t[i]-t[j]);            a[num].a=i*n+j;        }    }    sort(a+1,a+1+num,cmp);    l=1,r=num;    while(l<r){        mid=(l+r)/2;pan=a[mid].z;        memset(f,128,sizeof(f));f[0]=0;        fo(i,1,n){            fo(j,0,i-1){                if(g[i][j]<=pan&&f[i]<f[j]+1)f[i]=f[j]+1;            }        }        fo(i,1,n)if(f[i]>=m)break;            if(f[i]>=m)r=mid;else l=mid+1;    }    i=a[l].a/n,j=a[l].a%n;    ans1=ju(x[i],y[i],x[j],y[j]),ans3=abs(t[i]-t[j]);    fod(i,sqrt(ans1),1){        if(ans1%(i*i)==0){            ans2=ans1/(i*i);ans1=i;            break;            }    }    l=gcd(ans1,ans3);    ans1/=l,ans3/=l;    printf("%d %d %d\n",ans1,ans2,ans3);}
2 0
原创粉丝点击