zoj zju 3597 Hit the Target! 线段树 扫描线

这题很锻炼模型转换的能力http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3597

题意:有一排的枪编号依次为1~n 有一排靶子编号依次为1~m

告诉你哪些枪能打中哪些靶子,然后如果每次只能选连续的P把枪,连续的Q个靶子,每次能打中的靶子的最大值为多少

答案是把每次打中的最大值相加再除以总的次数

即选择 1~P 的枪能打中的最多的靶子的数量 + 2~p+1 的枪能打中的最多的靶子的数量 +。。。n-p+1~n的枪能打中的最多的靶子的数量 /(n-p+1)

注意,每把枪最多只能打一个靶子

 

解法:将题目中的关系转换为坐标 以枪为纵坐标 a 能打中 b ,在坐标系中为(b,a),然后连续的P把枪和连续的Q个靶子则可以表示为

用一个P x Q的矩形去覆盖,最多能覆盖的总的点数,就是poj 2482 了,但要注意一点,如果两根同一高度的水平线的距离小于Q,则重叠的部分职能算一次,因为每把枪只能打一个靶子

我的代码

View Code
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define lson l,m,x<<1
#define rson m+1,r,x<<1|1
const int maxn = 100010;
int Max[maxn<<2],col[maxn<<2];
struct point{
    int x,y;
    bool operator <(const point &cmp) const {
        return y<cmp.y || (y==cmp.y&&x<cmp.x);
    }
}pp[maxn];
inline int max(int a,int b){
    return a>b?a:b;
}
inline int min(int a,int b){
    return a<b?a:b;
}
void pushdown(int x){
    if(col[x]){
        Max[x<<1]+=col[x];
        Max[x<<1|1]+=col[x];
        col[x<<1]+=col[x];
        col[x<<1|1]+=col[x];
        col[x]=0;
    }
}
void build(int l,int r,int x){
    Max[x]=col[x]=0;
    if(l==r) return ;
    int m=(l+r)>>1;
    build(lson);
    build(rson);
}
void update(int L,int R,int val,int l,int r,int x){
    if(L<=l&&r<=R){
        col[x]+=val;
        Max[x]+=val;
        return ;
    }
    pushdown(x);
    int m=(l+r)>>1;
    if(L<=m) update(L,R,val,lson);
    if(R>m) update(L,R,val,rson);
    Max[x]=max(Max[x<<1],Max[x<<1|1]);
}

void solve(int n,int m,int p,int q,int K)
{
    int i,j,y0;
    double ret=0;
    build(1,m,1);
    i=j=0;
    for(y0=1;y0+p-1<=n;y0++)
    {
        for(;j<K && pp[j].y-y0 < p;j++)
        {
            if(j+1 < K && pp[j+1].y==pp[j].y && pp[j+1].x-pp[j].x < q)
                update(pp[j].x,pp[j+1].x-1,1,1,m,1);
            else
                update(pp[j].x,min(m,pp[j].x+q-1),1,1,m,1);
        }
        ret+=Max[1];
        for(;i<j&&pp[i].y==y0;i++)
        {
            if(i+1<j && pp[i+1].y==y0 && pp[i+1].x-pp[i].x < q)
                update(pp[i].x,pp[i+1].x-1,-1,1,m,1);
            else
                update(pp[i].x,min(pp[i].x+q-1,m),-1,1,m,1);
        }
    }
    printf("%.2lf\n",ret/(n-p+1));
}
int main()
{
    int t,n,m,p,q,k,i;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d%d%d%d",&n,&m,&p,&q,&k);
        for(i=0;i<k;i++)    scanf("%d%d",&pp[i].y,&pp[i].x);
        sort(pp,pp+k);
        solve(n,m,p,q,k);
    }
    return 0;
}
posted @ 2012-04-28 09:38  Because Of You  Views(527)  Comments(0Edit  收藏  举报