跪Po姐
状压枚举
每次Check的时候,对于每段时间显然先提高生产力再生产产品
那么我可以考虑这一段内先尽量提高生产力 但是这样可能会导致生产力提高得太高而没有足够的时间生产产品使得某个订单失败
因此我们计算出对于后面的每一个订单,最多花多少时间提高生产力可以满足如果用接下来的时间都生产的话不至于fail
由于产品数量是关于提高生产力次数的二次函数 因此解个方程就行了
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cmath>
using namespace std;
typedef long long ll;
inline char nc()
{
static char buf[100000],*p1=buf,*p2=buf;
if (p1==p2) { p2=(p1=buf)+fread(buf,1,100000,stdin); if (p1==p2) return EOF; }
return *p1++;
}
inline void read(ll &x)
{
char c=nc(),b=1;
for (;!(c>='0' && c<='9');c=nc()) if (c=='-') b=-1;
for (x=0;c>='0' && c<='9';x=x*10+c-'0',c=nc()); x*=b;
}
const ll N=25;
struct abcd{
ll t,g,m;
void read(){
::read(t); ::read(g); ::read(m);
}
bool operator < (const abcd &B) const{
return t<B.t;
}
}s[N],a[N];
ll tot;
ll n;
ll w,g,t,x;
inline ll Calc(double a,double b,double c){
double delta=b*b-4*a*c;
if (delta<0) return -1;
double x1,x2;
x1=(-b-sqrt(delta))/a/2; x2=(-b+sqrt(delta))/a/2;
if (x1>x2) swap(x1,x2);
return floor(x2);
}
inline bool Jud()
{
w=1; g=0;
for (int i=1;i<=tot;i++)
{
x=t=a[i].t-a[i-1].t;
ll tem=0;
for (int j=i;j<=tot;j++)
{
tem+=a[j].g;
if (tem>g)
x=min(x,Calc(-1,(a[j].t-a[i-1].t)-w,(a[j].t-a[i-1].t)*w+g-tem));
}
if (x<0) return 0;
g+=(w+=x)*(t-x);
g-=a[i].g;
}
return 1;
}
int main()
{
ll ans=0,tmp=0;
freopen("t.in","r",stdin);
freopen("t.out","w",stdout);
read(n);
for (int i=1;i<=n;i++)
s[i].read();
sort(s+1,s+n+1);
for (int i=0;i<(1<<n);i++)
{
tmp=tot=0;
for (int j=1;j<=n;j++)
if (i&(1<<(j-1)))
tmp+=s[j].m,a[++tot]=s[j];
if (Jud())
ans=max(ans,tmp);
}
printf("%lld\n",ans);
}