bzoj 2832
题解:
首先有一个比较显然的事情是如果我们确定了买的次数这道题就可以简单的贪心了
但是答案和买的次数是什么关系呢。。
好像是可以三分的 所以应该是单峰的
这里用了模拟退火,而且是没有处理失败情况的模拟退火
代码:
#include <bits/stdc++.h> #define ll long long using namespace std; const ll N=500; ll total,f,n,ans; struct re{ ll a,b; }a[N]; bool cmp(re x,re y) { return(x.a<y.a); } double Random() { return rand()/(double) RAND_MAX ;} /*ll judge(ll x) { if (x<=0) return 0; ll xx=total-f*x,day=0,res=0; for (ll i=1;i<=n;i++) { if (log2(x)+log2(a[i].a)>log2(xx)) { res+=xx/a[i].a; break; } ll num=min(xx/a[i].a/x,a[i].b-day+1); day+=num; xx-=num*a[i].a*x; res+=num*x; } ans=max(ans,res); return(res); }*/ ll judge(ll times) { if(times<=0) return 0; ll Money = total - times * f; ll res = 0, num, day = 0; for(int i=1;i<=n;i++) { num = min(Money / a[i].a / times, a[i].b - day + 1); Money -= num * a[i].a * times; day += num; res += times * num; if(day <= a[i].b) { num = Money / a[i].a; res += num; ans = max(ans, res); return res; } } ans = max(ans, res); return res; } void sa(double T) { ll now=1; while (T>=1) { ll a=now+(ll)(T*(Random()*2-1)); if (a<=0) a=T*Random(); ll de=judge(a)-judge(now); if (de>0) now=a; T*=0.97; } } /*void sa(double T) { ll Now = 1; while(T >= 1) { ll A = Now + (ll)(T * (Random()*2-1)) ; if(A<=0) A = T*Random(); ll dE = judge(A) - judge(Now); if(dE > 0) Now = A; T *= 0.97; } }*/ int main() { srand(time(0)^size_t(new char)); freopen("1.in","r",stdin); freopen("1.out","w",stdout); ios::sync_with_stdio(false); while (cin>>total>>f>>n) { ans=0; for(ll i=1;i<=n;i++) cin>>a[i].a>>a[i].b; sort(a+1,a+n+1,cmp); ll m=n,d=-1; n=0; for (ll i=1;i<=m;i++) if (a[i].b>d) a[++n]=a[i],d=a[i].b; sa(total/f+1); cout<<ans<<endl; } return 0; }