【jzoj4783】【Osu】

题目大意

给出一些按顺序出现的点(x,y)和出现时间,问经过k个点所需要的最小速度,初始在(0,0)速度要保留根号。

解题思路

答案可能值有n^2个(两两点对),二分答案后n^2dp判断即可。

code

#include
#include
#include
#include
#include
#define LF double
#define LL long long
#define max(n1,n2) ((n1>n2)?n1:n2)
#define min(n1,n2) ((n1>n2)?n2:n1)
#define fo(i,j,k) for(int i=j;i<=k;i++)
#define fd(i,j,k) for(int i=j;i>=k;i--)
using namespace std;
int const maxn=2000,inf=2147483647;
int n,K,t[maxn+10],x[maxn+10],y[maxn+10],f[maxn+10],dis[maxn+10][maxn+10],tim[maxn+10][maxn+10];
int gc(int x,int y){
    int z;if(!y)return 1;
    for(;z=x%y;){
        x=y;
        y=z;
    }
    return y;
}
struct rec{
    int x,y,t,d;
    friend bool operator<(rec x,rec y){
        return 1ll*x.d*y.t<1ll*y.d*x.t;
    }
};
rec an[(maxn+10)*(maxn+10)];
int main(){
    freopen("d.in","r",stdin);
    freopen("d.out","w",stdout);
    scanf("%d%d",&n,&K);
    fo(i,1,n)scanf("%d%d%d",&t[i],&x[i],&y[i]);
    int cnt=0;
    fo(i,0,n)
        fo(j,i+1,n)
            if(i+n-j+1>=K){
                an[++cnt].x=abs(x[i]-x[j]),
                an[cnt].y=abs(y[i]-y[j]),
                tim[i][j]=an[cnt].t=(t[i]-t[j])*(t[i]-t[j]),
                dis[i][j]=an[cnt].d=an[cnt].x*an[cnt].x+an[cnt].y*an[cnt].y;
            }
    sort(an+1,an+cnt+1);
    int l=1,r=cnt;
    for(;l!=r;){
        int m=(l+r)/2,ans=0;
        fo(i,1,n)f[i]=-inf;f[0]=0;
        fo(i,1,n){
            fo(j,0,i-1)
                if(1ll*dis[j][i]*an[m].t<=1ll*an[m].d*tim[j][i])f[i]=max(f[i],f[j]+1);
            ans=max(ans,f[i]);
            if(ans>=K)break;
        }
        if(ans>=K)r=m;
        else l=m+1;
    }
    int a=1,b=an[l].d,c=sqrt(an[l].t);
    fo(i,2,28284)
        for(;b%(i*i)==0;a*=i,b/=i*i);
    int gcd=gc(a,c);a/=gcd;c/=gcd;
    printf("%d %d %d",a,b,c);
    return 0;
}

你可能感兴趣的:(jzoj4783,osu,动态规划,jzoj,二分,三分)