LUOGU P3161 [CQOI2012]模拟工厂 (贪心)

传送门

解题思路

贪心,首先因为\(n\)比较小,可以\(2^n\)枚举子集。然后判断的时候就每次看后面的如果用最大生产力生产能不能达成目标,解一个二次函数。

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define int long long
 
using namespace std;
const int MAXN = 25;
typedef long long LL;

inline int rd(){
    int x=0,f=1;char ch=getchar();
    while(!isdigit(ch)) {f=ch=='-'?0:1;ch=getchar();}
    while(isdigit(ch))  {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
    return f?x:-x;
}

int n,t[MAXN],g[MAXN],m[MAXN],cnt,mk[MAXN],ans;
int tmp[MAXN];

inline bool cmp(int x,int y){
    return t[x]<t[y];
}

int calc(int a,int b,int c){
    double delta=b*b-4*a*c;
    if(delta<0) return -1;
    return floor((-b+sqrt(delta))/(a*2));
}

inline bool check(){
    for(int i=1;i<=cnt;i++) tmp[i]=mk[i];
    sort(tmp+1,tmp+1+cnt,cmp);
    int tt,now=1;LL sum=0,res=0;
    for(int i=1;i<=cnt;i++){
        sum=0;tt=t[tmp[i]]-t[tmp[i-1]];
        for(int j=i;j<=cnt;j++){
            sum+=g[tmp[j]];
            if(sum>res)
                tt=min(tt,calc(1,now-t[tmp[j]]+t[tmp[i-1]],
                sum-res-now*(t[tmp[j]]-t[tmp[i-1]])));
        }
        if(tt<0) return false;
        now+=tt;res+=(now*(t[tmp[i]]-t[tmp[i-1]]-tt)-g[tmp[i]]);
    }
    return true;
}

void dfs(int x,LL sum){
    if(x==n+1) {if(sum>ans) if(check()) ans=sum;return;}
    mk[++cnt]=x;dfs(x+1,sum+m[x]);
    cnt--;dfs(x+1,sum);
}

signed main(){
//  freopen("data.txt","r",stdin);
//  freopen("B.txt","w",stdout);
    n=rd();
    for(int i=1;i<=n;i++) t[i]=rd(),g[i]=rd(),m[i]=rd();
    dfs(1,0);cout<<ans;
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/sdfzsyq/p/9812761.html