题解:P10884 [COCI 2017-2018#2] San
xiaoliebao1115 · · 题解
小清新双向搜索题,难度比卖瓜稍难吧。
idea
双向搜索
看到
对于左半边搜索,每个点枚举经过和不经过。搜索到最后记录这次搜索的总金币数以及最后一个经过的位置的高度
对于右半边搜索,记录的是第一个经过的位置的高度
我们把左半边搜索的总金币数记为
二维偏序
根据题目要求的限制可以得出:
具体的,把所有搜索得到的结果都存入一个结构体数组中,先对
对于左边搜到的,将
code
const int nn=41,mm=(1<<20)+5,kk=1e9,hyf=1<<21;//膜拜hhhyyyfff大佬
int n,h[nn],cnt;
ll g[nn],k,ans;
int tree[mm<<1];
inline void add(int x){//树状数组
for(int i=x;i<=hyf;i+=i&(-i)) tree[i]++;
}
inline int query(int x){
int tot=0;
for(int i=x;i>=1;i-=i&(-i)) tot+=tree[i];
return tot;
}
struct node{
int h,tp;
ll g;
};
node x[mm<<1];
inline bool cmp(node l1,node l2){
return l1.g<l2.g;
}
inline bool cmp2(node l1,node l2){
if(l1.h==l2.h) return l1.tp<l2.tp;
return l1.h<l2.h;
}
inline void dfs(int wz,ll sum,int lst){
if(wz>n/2){
cnt++;
x[cnt].h=lst,x[cnt].g=k-sum>0?k-sum:0;
return ;
}
if(lst<=h[wz]) dfs(wz+1,sum+g[wz],h[wz]);
dfs(wz+1,sum,lst);
}//搜索左边
inline void dfs2(int wz,ll sum,int lst){
if(wz<=n/2){
cnt++;
x[cnt].h=lst,x[cnt].g=sum,x[cnt].tp=1;
return ;
}
if(lst>=h[wz]) dfs2(wz-1,sum+g[wz],h[wz]);
dfs2(wz-1,sum,lst);
}//搜索右边
int main(){
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
cin>>n>>k;
for(int i=1;i<=n;i++) cin>>h[i]>>g[i];
dfs(1,0,0);
dfs2(n,0,kk);
sort(x+1,x+cnt+1,cmp);
int mzhxi=0;
ll prvg=-1,bfg;
for(int i=1;i<=cnt;i++){
bfg=x[i].g;
if(x[i].g==prvg) x[i].g=mzhxi;
else x[i].g=++mzhxi;
prvg=bfg;//离散化
}
sort(x+1,x+cnt+1,cmp2);
for(int i=1;i<=cnt;i++){
if(x[i].tp){
ll sum=query(x[i].g);
ans+=sum;
}
else add(x[i].g);
}
cout<<ans<<endl;
return 0;
}
时间复杂度