1. 程式人生 > >LUOGU P3161 [CQOI2012]模擬工廠 (貪心)

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;
}