JZOJ 3512. 【NOIP2013模拟11.5A组】游戏节目

目录:


题目:

单击查看题目


分析:

分两步处理:
第一步:把问题简单化,假设没有k的限制,设求出来的方案总数是x。
第二步:考虑k的限制,由于k<7,可以穷举n个节目取0个,n个节目取1个,n个节目取2个,n个节目取3个,n个节目取3个,n个节目取4个,n个节目取5个,n个节目取6个,穷举完这几种情况就可以知道哪些方案是合法的。而且 C ( 34 , 0 ) + C ( 34 , 1 ) + C ( 34 , 2 ) + C ( 34 , 3 ) + C ( 34 , 4 ) + C ( 34 , 5 ) + C ( 34 , 6 ) = 1676116
也就是这个穷举不超过1676116次。设第二步的方案总数是y。
那么,最后应该输出的答案就是x - y。
第二步的方案数y可以搜索计算结果,下面重点讲讲第一步的方案数x如何求。
由于n最大是34,直接搜索会超时。可以把n个节目平均分成两部分,即第1至第 n / 2 个节目归为第1部分,第 n / 2 + 1 个节目至第n个节目归为第2部分。
第1部分:显然最多只有17个节目,每个节目可以取或者不取,穷举这17个节目的所有情况,显然有 2 1 7 种取法,对于每一种取法,队伍A都有一个得分,设为scoreA, 队伍B也有一个得分scoreB,队伍C也有一个得分scoreC。不妨设difAB1 = scoreA - scoreB, difAC1 = scoreA - scoreC,即每一种取法,都可以计算出一对值(difAB1,difAC1),
第2部分:显然最多也只有17个节目。每个节目可以取或者不取,穷举这17个节目的所有情况,显然也是有 2 1 7 种取法。同理,对于每一种取法,设difAB1 = scoreA - scoreB, difAC1 = scoreA - scoreC,即每一种取法都可以计算出一对值(difAB2,difAC2),
显然,如果一个方案要成立,必须要同时满足:
d i f A B 1 + d i f A B 2 > 0 (即队伍A的总得分比队伍B的总得分高)
d i f A C 1 + d i f A C 2 > 0 (即队伍A的总得分比队伍C的总得分高)
于是,问题转化为,枚举一对值(difAB1,difAC1),在第2部分里面查询有多少对(difAB2,difAC2),使得同时满足
d i f A B 1 + d i f A B 2 > 0
d i f A C 1 + d i f A C 2 > 0
显然,对于第2部分,可以用树状数组或者线段树之类的数据结构进行保存,以备第1部分的查询所需。
由于分两步求答案,于是时间复杂度 = O ( x + y = 2 17 L o g ( 2 17 ) + 1676116 )


代码:

#pragma GCC optimize("3")
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#define N 40
#define M 150000
#define IL inline
#define LL long long
#define re register
#define r(i,a,b) for(i=a;i<=b;i++)
#define getchar() (S==T&&(T=(S=BB)+fread(BB,1,1<<15,stdin),S==T)?EOF:*S++)
#define lb(x) x&-x
using namespace std;LL f,i,j,n,k,s,t1,t2,ans1,ans2;char c;
char BB[1<<15],*S=BB,*T=BB;
LL A[N],B[N],C[N],t[M<<1];
LL ab1[M],ac1[M],ab2[M],ac2[M];
struct node{LL x,y,z;}d[M<<1];
IL LL read()
{
    f=0;re char c; 
    while(c=getchar(),c<=47||c>=58);f=(f<<3)+(f<<1)+c-48;
    while(c=getchar(),c>=48&&c<=57) f=(f<<3)+(f<<1)+c-48;
    return f;
}
IL void dg(re LL w,re LL l,re LL x,re LL y,re LL z)
{
    if(w>i){if(x>y&&x>z) ans1++;return;}
    for(re LL j=l+1;j<=n;j++) dg(w+1,j,x+A[j],y+B[j],z+C[j]);
    return;
}
IL void dfs1(re LL l,re LL x,re LL y,re LL z)
{
    t1++;ab1[t1]=x-y;ac1[t1]=x-z;
    for(LL j=l+1;j<=n>>1;j++) dfs1(j,x+A[j],y+B[j],z+C[j]);
    return;
}
IL void dfs2(re LL l,re LL x,re LL y,re LL z)
{
    t2++;ab2[t2]=y-x;ac2[t2]=z-x;
    for(LL j=l+1;j<=n;j++) dfs2(j,x+A[j],y+B[j],z+C[j]);
    return;
}
IL bool cmp1(re node x,re node y){return x.y<y.y;}
IL bool cmp2(re node x,re node y){return x.x<y.x||x.x==y.x;}
IL void add(LL sx,LL x)
{
    for(;x<=sx;x+=lb(x)) t[x]++;
    return;
}
IL LL ask(LL x)
{
    LL ans=0;
    for(;x;x-=lb(x)) ans+=t[x];
    return ans;
}
signed main()
{
    freopen("show.in","r",stdin);
    freopen("show.out","w",stdout);
    n=read();k=read();
    r(i,1,n) A[i]=read();
    r(i,1,n) B[i]=read();
    r(i,1,n) C[i]=read();
    r(i,1,~-k) dg(1,0,0,0,0);
    dfs1(0,0,0,0);
    dfs2(n>>1,0,0,0);
    r(i,1,t1) d[i]=(node){ab1[i],ac1[i],1};
    r(i,1,t2) d[i+t1]=(node){ab2[i],ac2[i],2};
    sort(d+1,d+1+t1+t2,cmp1);
    LL e=1,l=1;
    d[t1+t2+1].y=-2147483647;
    r(i,2,t1+t2+1) if(d[i].y!=d[~-i].y)
    {
        r(j,l,~-i) d[j].y=e;
        e++;l=i;
    }
    e--;
    sort(d+1,d+1+t1+t2,cmp2);
    LL g,o=0;
    while(o<=t1+t2)
    {
        g=d[o].x;l=o;
        while(d[o].x==g&&o<=t1+t2) o++;
        r(i,l,o-1) if(d[i].z==1) ans2+=ask(~-d[i].y);
        r(i,l,o-1) if(d[i].z==2) add(e,d[i].y);
    }
    printf("%lld",ans2-ans1);
}

猜你喜欢

转载自blog.csdn.net/qq_35786326/article/details/81106312