BZOJ 3703: 昊昊的壮举之造福社会

传送门

搜索,剪枝

首先可以二分答案迭代加深,假设要买 $p$ 台

那么肯定卖价格最小的 $p$ 台

再来个 $A*$ ,设搜到当前情况时,有 $waste$ 的钱一定要被浪费(其实就是某些学校剩下的钱连最便宜的都买不起)

设最便宜的 $p$ 台电脑总价值为 $sum$ ,所有学校的总钱数为 $S$,那么我们最多浪费 $S-tot$,如果 $waste>S-tot$ 就直接返回

但是显然还是不够

看看数据发现相同价格的电脑和相同初始钱数的学校数量很多

不妨使搜索时保证,对于相同价格的电脑,购买的学校的初始钱数单调不增,显然这样不会影响搜索时的正确性

然后就可以跑过了

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
typedef long long ll;
inline int read()
{
    int x=0,f=1; char ch=getchar();
    while(ch<'0'||ch>'9') { if(ch=='-') f=-1; ch=getchar(); }
    while(ch>='0'&&ch<='9') { x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); }
    return x*f;
}
const int N=5e5+7;
int n,m,mon[N],cst[N],ans;
int S,sum[N],Mx,Las[N];
bool GG;
void dfs(int pos,int waste)
{
    if(waste>Mx) return;
    if(!pos) { GG=1; return; }
    int R=Las[cst[pos]];
    for(int i=R;i;i--)
    {
        if(cst[pos]>mon[i]) continue;
        mon[i]-=cst[pos]; Las[cst[pos]]=i;
        dfs(pos-1,waste+ (mon[i]<cst[1])*mon[i] );
        mon[i]+=cst[pos];
        if(GG) return;//记得先还原mon再返回
    }
    Las[cst[pos]]=R;
}
bool check(int p)
{
    if(sum[p]>S||cst[p]>mon[m]) return 0;
    GG=0; Mx=S-sum[p];
    for(int i=1;i<=n;i++) Las[cst[i]]=m;//每次都要初始化Las
    dfs(p,0); return GG;
}
int main()
{
    m=read();
    for(int i=1;i<=m;i++) mon[i]=read(),S+=mon[i];
    n=read();
    for(int i=1;i<=n;i++) cst[i]=read();
    sort(mon+1,mon+m+1); sort(cst+1,cst+n+1);
    for(int i=1;i<=n;i++) sum[i]=sum[i-1]+cst[i];
    int L=0,R=n;
    while(L<=R)
    {
        int mid=L+R>>1;
        if(check(mid)) L=mid+1,ans=mid;
        else R=mid-1;
    }
    printf("%d\n",ans);
    return 0;
}

 

posted @ 2019-08-06 13:26  LLTYYC  阅读(206)  评论(0编辑  收藏  举报