zoj 3597 Hit the Target! (线段树)

来源:互联网 发布:阿里云认证 有用吗 编辑:程序博客网 时间:2024/06/16 19:20

题意:有n个枪和m个靶子,每个枪只有一颗子弹,给出枪能达到的靶子,现在有同等的概率的选择连续p个枪,然后选择连续q个靶子,使得能获得的分数最大,问最后获得分数的期望。

思路:可以枚举一下选择连续p个枪的区间,然后维护能够打到的靶子的最大数量,就能解决这个问题了。用线段树保存用当前的枪能打到的,以x为右端点,左边连续q个靶子的分数总和,那么对于每枝枪,更新区间[y,min(y+q-1,m))]即可。由于同一枝枪有可能可以打多个靶子,但是只有一发子弹,因此,更新这个区间的时候不能不能相互覆盖,这里排下序就可以解决了。

代码:

#include<iostream>#include<cstdio>#include<cstring>#include<string>#include<algorithm>#include<map>#include<queue>#include<stack>#include<cmath>#include<vector>#define inf 0x3f3f3f3f#define Inf 0x3FFFFFFFFFFFFFFFLL#define eps 1e-9#define pi acos(-1.0)using namespace std;typedef long long ll;const int maxn=500000+10;vector<pair<int,int> >shot[maxn];int maxv[maxn<<2],addv[maxn<<2];inline void PushUp(int rt){    maxv[rt]=max(maxv[rt<<1],maxv[rt<<1|1]);}inline void PushDown(int rt){    if(addv[rt])    {        addv[rt<<1]+=addv[rt];        addv[rt<<1|1]+=addv[rt];        maxv[rt<<1]+=addv[rt];        maxv[rt<<1|1]+=addv[rt];        addv[rt]=0;    }}void build(int l,int r,int rt){    maxv[rt]=addv[rt]=0;    if(l==r) return ;    int m=(l+r)>>1;    build(l,m,rt<<1);    build(m+1,r,rt<<1|1);}void Update(int L,int R,int l,int r,int rt,int v){    if(l>=L&&r<=R)    {        addv[rt]+=v;        maxv[rt]+=v;        return ;    }    PushDown(rt);    int m=(l+r)>>1;    if(m>=L) Update(L,R,l,m,rt<<1,v);    if(m<R) Update(L,R,m+1,r,rt<<1|1,v);    PushUp(rt);}int main(){    //freopen("in.txt","r",stdin);    //freopen("out.txt","w",stdout);    int t,n,m,p,q;    scanf("%d",&t);    while(t--)    {        scanf("%d%d%d%d",&n,&m,&p,&q);        memset(shot,0,sizeof(shot));        for(int i=0;i<=n;++i) shot[i].clear();        int k,L,R,last;        scanf("%d",&k);        while(k--)        {            scanf("%d%d",&L,&R);            shot[L].push_back(make_pair(R,min(R+q-1,m)));        }        for(int i=1;i<=n;++i)            sort(shot[i].begin(),shot[i].end());        build(1,m,1);        double ans=0,r=1.0/(n-p+1);        for(int i=1;i<=n;++i)        {            if(i<=n)            {                last=0;                for(int j=0;j<(int)shot[i].size();++j)                {                    L=shot[i][j].first;                    R=shot[i][j].second;                    if(R<=last) continue;                    L=max(L,last+1);                    Update(L,R,1,m,1,1);                    last=R;                }            }            if(i>=p)            {                k=i-p;                if(k)                {                    last=0;                    for(int j=0;j<(int)shot[k].size();++j)                    {                        L=shot[k][j].first;                        R=shot[k][j].second;                        if(R<=last) continue;                        L=max(L,last+1);                        Update(L,R,1,m,1,-1);                        last=R;                    }                }                ans+=r*maxv[1];            }        }        printf("%.2lf\n",ans);    }    return 0;}


0 0
原创粉丝点击