您的位置:首页 > 其它

JZOJ-senior-3512. 【NOIP2013模拟11.5A组】游戏节目(show)

2018-01-11 18:38 330 查看

3512. 【NOIP2013模拟11.5A组】游戏节目(show)

(File IO): input:show.in output:show.out

Time Limits: 1000 ms Memory Limits: 262144 KB Detailed Limits

Description

有三支队伍,分别是A,B,C。有n个游戏节目,玩第i个游戏,队伍A可以得到的分数是A[i],队伍B可以得到的分数是B[i],队伍C可以得到的分数是C[i]。由于时间有限,可能不是每个节目都能玩,于是节目主持人决定要从n个游戏节目里面挑选至少k个节目出来(被选中的节目不分次序),使得队伍A成为赢家。队伍A能成为赢家的条件是队伍A的总得分要比队伍B的总得分要高,同时也要比队伍C的总得分要高。节目主持人有多少种不同的选取方案?

Input

第一行,两个整数n和k。

第二行, n个整数,分别是A[1]、A[2]、A[3]…A


第三行, n个整数,分别是B[1]、B[2]、B[3]…B


第四行, n个整数,分别是C[1]、C[2]、C[3]…C


Output

一个整数,表示不同的选取方案数量。

Sample Input

3 2

1 1 2

1 1 1

1 1 1

Sample Output

3

【样例解释】

方案一:选取节目1和节目3。

方案二:选取节目2和节目3。

方案三:选取节目1、节目2、节目3。


Data Constraint

对于40%数据,2 <= n <= 20。

对于100%数据,2 <= n <= 34, 1 <= k <= min(n,7), 1 <=A[i], B[i], C[i]<= 10^9。

题解

分两步处理:

第一步:把问题简单化,假设没有k的限制,设求出来的方案总数是x。

第二步:考虑k的限制,由于k<7,可以穷举n个节目取0个,n个节目取1个,n个节目取2个,n个节目取3个,n个节目取3个,n个节目取4个,n个节目取5个,n个节目取6个,穷举完这几种情况就可以知道哪些方案是合法的。而且Combinations(34,0) + Combinations(34,1) + Combinations(34,2) + Combinations(34,3) + Combinations(34,4) + Combinations(34,5) + Combinations(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^17种取法,对于每一种取法,队伍A都有一个得分,设为scoreA, 队伍B也有一个得分scoreB,队伍C也有一个得分scoreC。不妨设difAB1 = scoreA - scoreB, difAC1 = scoreA - scoreC,即每一种取法,都可以计算出一对值(difAB1,difAC1),

第2部分:显然最多也只有17个节目。每个节目可以取或者不取,穷举这17个节目的所有情况,显然也是有2^17种取法。同理,对于每一种取法,设difAB1 = scoreA - scoreB, difAC1 = scoreA - scoreC,即每一种取法都可以计算出一对值(difAB2,difAC2),

显然,如果一个方案要成立,必须要同时满足:

difAB1 + difAB2 > 0 (即队伍A的总得分比队伍B的总得分高)

difAC1 + difAC2 > 0 (即队伍A的总得分比队伍C的总得分高)

于是,问题转化为,枚举一对值(difAB1,difAC1),在第2部分里面查询有多少对(difAB2,difAC2),使得同时满足

difAB1 + difAB2 > 0

difAC1 + difAC2 > 0

显然,对于第2部分,可以用树状数组或者线段树之类的数据结构进行保存,以备第1部分的查询所需。

由于分两步求答案,于是时间复杂度 = x + y = 2^17 * Log(2^17) + 1676116

Code

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#define N 40
#define M 150000
#define ll long long
#define fo(i,a,b) for(i=a;i<=b;i++)
using namespace std;
ll i,j,n,k,s,t1,t2,ans1,ans2;
ll a
,b
,c
,tr[4*M];
ll ab1[M],ac1[M],ab2[M],ac2[M];
struct node{ll x,y,z;}d[2*M];
void dg(ll w,ll l,ll x,ll y,ll z)
{
if (w>i) {if (x>y && x>z) ans1++; return;}
for(ll j=l+1; j<=n; j++) dg(w+1,j,x+a[j],y+b[j],z+c[j]);
}
void dfs1(ll l,ll x,ll y,ll z)
{
t1++,ab1[t1]=x-y,ac1[t1]=x-z;
for(ll j=l+1; j<=n/2; j++) dfs1(j,x+a[j],y+b[j],z+c[j]);
}
void dfs2(ll l,ll x,ll y,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]);
}
bool cmd(node p,node q)
{
return p.y<q.y;
}
bool cmp(node p,node q)
{
return p.x<q.x || p.x==q.x && p.y<q.y;
}
void find(ll x,ll st,ll en,ll l,ll r)
{
if (l>r) return;
if (st==l && en==r) {s+=tr[x]; return;}
ll m=(st+en)>>1;
if (r<=m) find(x+x,st,m,l,r);
else if (l>m) find(x+x+1,m+1,en,l,r);
else find(x+x,st,m,l,m),find(x+x+1,m+1,en,m+1,r);
}
void change(ll x,ll l,ll r,ll p)
{
if (l==r) {tr[x]++; return;}
ll m=(l+r)>>1;
if (p<=m) change(x+x,l,m,p);
else change(x+x+1,m+1,r,p);
tr[x]=tr[x+x]+tr[x+x+1];
}
int main()
{
freopen("show.in","r",stdin);
freopen("show.out","w",stdout);
scanf("%lld%lld",&n,&k);
fo(i,1,n) scanf("%lld",&a[i]);
fo(i,1,n) scanf("%lld",&b[i]);
fo(i,1,n) scanf("%lld",&c[i]);
fo(i,1,k-1) dg(1,0,0,0,0);
dfs1(0,0,0,0);
dfs2(n/2,0,0,0);
fo(i,1,t1) d[i].x=ab1[i],d[i].y=ac1[i],d[i].z=1;
fo(i,1,t2) d[i+t1].x=ab2[i],d[i+t1].y=ac2[i],d[i+t1].z=2;
sort(d+1,d+1+t1+t2,cmd);
ll e=1,l=1;
d[t1+t2+1].y=-2147483647;
fo(i,2,t1+t2+1) if (d[i].y!=d[i-1].y)
{
fo(j,l,i-1) d[j].y=e;
e++,l=i;
}
e--;
sort(d+1,d+1+t1+t2,cmp);
ll g,o=0;
while (o<=t1+t2)
{
g=d[o].x,l=o;
while (d[o].x==g && o<=t1+t2) o++;
fo(i,l,o
b870
-1) if (d[i].z==1) s=0,find(1,1,e,1,d[i].y-1),ans2+=s;
fo(i,l,o-1) if (d[i].z==2) change(1,1,e,d[i].y);
}
printf("%lld",ans2-ans1);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  线段树 搜索 排序 DFS