当前位置: 首页 > 工具软件 > Twinkle > 使用案例 >

upcoj 2525 Twinkle Twinkle Little Star 题解

洪承天
2023-12-01

题目链接:upc2525: Twinkle Twinkle Little Star

Twinkle Twinkle Little Star


Twinkle, twinkle, little star, how I wonder what you are.

Up above the world so high, like a diamond in the sky.

Twinkle, twinkle, little star, how I wonder what you are.

When the blazing sun is gone, when he nothing shines upon.

The you show your little light, Twinkle, twinkle, little star

Twinkle, twinkle, little star, How I wonder what you are.

Twinkle, twinkle, little star, how I wonder what you are.

----<Twinkle, twinkle, little star.>

 

Well, this song may take us back to our childhood. When we were young, we often looked up at the stars. How amazing they were! But, unfortunately, as we are becoming older and older, what used to be interesting can not interest us now. So what we can do is to find something more interesting!

Here is one, maybe. Assume that all the stars are so far from us that we can treat them as points in a plane. You are given N stars in the plane, and a number K (0≤K≤N). What you need to do is to find the minimum square covering at least K stars, whose edges are all parallel to the axis. The stars which are on the edges of the square are also covered.

Input

The input will consist of multiple cases. Your program should process to the end of the input file.In the first line of one case, there are two integer N and K, 0<N≤1500, 0≤K≤N.

The next N lines are the description of the stars, one star per line. The ith line consists of two integers Xi and Yi, |Xi|<1000000, |Yi|<1000000.

Output

The output will consist of one line for each case, in the format of “Case X: Y”, while X is the case number counting from 1, and Y is the edge length of the minimum square. X and Y are all integers.

Sample Input

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

Sample Output

Case 1: 2
Case 2: 1

HINT

Huge input, scanf is recommended.


惯例,比赛的时候没思路。。。
大致意思就是在一个1000000*1000000的平面中有N<1500个点,要求用一个正方形来围住至少K个点,求这个正方形的最小边长。

首先想到应该是对X和有分别离散化,然后得到一个1500*1500的平面,然后枚举这个平面中的所有点作为正方形右下顶点(由于点不一定在最小的正方形顶点上 也可以在边上),然后二分枚举答案,只要能够在O(1)的复杂度来判断是否有K个,可以用dp对离散化后的平面进行处理。


渣渣代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#include<algorithm>
#include<cmath>
#define rep(i,j,n) for(int i=j;i<n;i++)
#define repd(i,j,n) for(int i=j;i>n;i--)
#define N 1505
using namespace std;
struct node
{
    int x,y;
} digt[N];
int indexx[N];
int indey[N];
int lx,ly;
int n,k;
int getx(int x)
{
 
    return int(lower_bound(indexx,indexx+lx,x)-indexx);
}
int gety(int y)
{
    return int(lower_bound(indey,indey+ly,y)-indey);
}
int dp[N][N];
void init()
{
    memset(dp,0,sizeof(dp));
    for(int i=0; i<n; i++)//将点对应到离散化后的平面上
    {
        int x1=getx(digt[i].x);
        int y1=gety(digt[i].y);
        dp[x1][y1]++;
    }
 
    for(int i=1; i<ly; i++)
        dp[0][i]=dp[0][i-1]+dp[0][i];
    for(int i=1; i<lx; i++)
        dp[i][0]=dp[i-1][0]+dp[i][0];
    for(int i=1; i<lx; i++)
        for(int j=1; j<ly; j++)
            dp[i][j]=dp[i-1][j]+dp[i][j-1]-dp[i-1][j-1]+dp[i][j]; //dp[i][j]表示0,0到i,j矩阵中点的个数
 
}
int nextx[N],nexty[N];//nextx[i]表示x轴上离散化第i个点在加上实际Len的值后在离散化平面上的位置
bool solve(int len)
{
//--------------------------------------------------------
    int t=0;
    for(int i=0; i<lx; i++)
    {
        for(; t<lx; t++)
            if(indexx[i]+len<indexx[t])break;
 
        nextx[i]=t-1;
    }
    t=0;
    for(int i=0; i<lx; i++)
    {
        for(; t<lx; t++)
            if(indey[i]+len<indey[t])break;
        nexty[i]=t-1;
    } 
    //这里求出实际边长对应在离散化后的x,y的差,
//-----------------------------------------------------------
    
    int x1,y1;
    for(int i=0; i<lx; i++)
        for(int j=0; j<ly; j++)
        {
            x1=nextx[i];
            y1=nexty[j];
 
            int ll=0,rr=0,lr=0;//分别表示这个矩阵的左边,右边,和左下面积上的点数目
            if(i>0)ll=dp[i-1][y1];
            if(j>0)rr=dp[x1][j-1];
            if(i>0&&j>0)
                lr=dp[i-1][j-1];
 
            if(dp[x1][y1]-ll-rr+lr>=k)return true;
 
        }
    return false;
}
int main()
{
    //freopen("test.txt","r",stdin);
 
    int test=1;
    while(scanf("%d%d",&n,&k)!=EOF)
    {
 
        for(int i=0; i<n; i++)
        {
            scanf("%d%d",&digt[i].x,&digt[i].y);
            indexx[i]=digt[i].x; 
            indey[i]=digt[i].y;
        }
        sort(indexx,indexx+n); //对X轴离散化
        sort(indey,indey+n);//对Y轴离散化
        lx=unique(indexx,indexx+n)-indexx;
        ly=unique(indey,indey+n)-indey;
 
        init();//预处理 
        int l=0,r=2000005;
        while(l<r)//二分枚举边长
        {
            int  mid=(l+r)>>1;
            if(solve(mid))r=mid;
            else l=mid+1;
        }
        printf("Case %d: %d\n",test++,l);
    }
    return 0;
}
 
/**************************************************************
    Problem: 2525
    User: 11072215
    Language: C++
    Result: Accepted
    Time:176 ms
    Memory:10156 kb
****************************************************************/





 类似资料: