【NOIP模拟】Osu

Solution

【NOIP模拟】Osu_第1张图片

Description

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

Code

#include
#include
#include
#include
#include
#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.zint 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(l2;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]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);
}

你可能感兴趣的:(noip,DP,二分)