zoukankan      html  css  js  c++  java
  • 【题解】CF1056F Write the Contest(三分+贪心+DP)

    【题解】CF1056F Write the Contest(三分+贪心+DP)

    最优化问题的三个解决方法都套在一个题里了,真牛逼

    最优解应该是怎样的,一定存在一种最优解是先完成了耗时长的任务再干别的(不干白不干啊),所以我们按照耗时先排序。

    假设你最优解是去事件(e_1,e_2,e_3,e_4),你可以在规定时间里干完,那么你如果按照耗时从大往小干也一定可以干完。

    好像只能找到"按照耗时从大往小干"一种钦定方法使得所有方案可以归纳到这种情况

    考虑最终耗时是怎样的:(t)表示练习用的时间

    [f(t)=dfrac {sum(dfrac {10} 9)^i a_{h_i}} {s_0+Ct}+10t ]

    我们转化一下思路,设(dp(i,j))表示选择(i)个任务做并且将会获得收益(j)的的最小的(sum(dfrac {10} 9)^i a_{h_i}),这样的设置状态类似于那个Jury一题,【题解】Jury Compromise(链表+DP)。转移显然不讲了。

    现在我们要使得(f(t)=dfrac {dp(i,j)} {s_0+Ct}+10t)满足条件并且使得(j)最大,由于(i,jle O(n))所以直接(n^2)枚举即可,现在的问题就变成了最小化这个东西(f(t)),显然这个函数有单峰且最小(类双勾函数),所以直接三分即可。

    //@winlere
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    
    
    using namespace std;  typedef long long ll;
    inline int qr(){
          register int ret=0,f=0;
          register char c=getchar();
          while(c<48||c>57)f|=c==45,c=getchar();
          while(c>=48&&c<=57) ret=ret*10+c-48,c=getchar();
          return f?-ret:ret;
    }
    const int maxn=1001;
    long double dp[maxn][maxn];
    const long double delta=(long double)9/10;
    const long double eps=1e-5;
    typedef pair < int , int > P;
    P data[maxn];
    //    a    c
    
    #define f(x) ((  (x)+dp[t][k]/(1+C*(x))   ))
          
    long double mi[maxn];
    int main(){
          //freopen("gamemag.in","r",stdin);
          //freopen("gamemag.out","w",stdout);
          mi[0]=1;
          for(register int t=1;t<maxn;++t) mi[t]=mi[t-1]/delta;
          for(register int T00=qr();T00;--T00){
    	    int n;
    	    long double C,T;
    	    cin>>n>>C>>T;
    	    for(register int t=1;t<=n;++t)
    		  data[t].first=qr(),data[t].second=qr();
    	    sort(data+1,data+(int)n+1,[](const P&a,const P&b){return a>b;});
    	    for(register int t=0;t<maxn;++t)
    		  for(register int i=0;i<maxn;++i)
    			dp[t][i]=1e18;
    	    dp[0][0]=0;
    	    for(register int t=1;t<=n;++t){
    		  for(register int i=t;i;--i){
    			for(register int k=data[t].second;k<=i*10;++k){
    			      dp[i][k]=min(dp[i][k],dp[i-1][k-data[t].second]+data[t].first*mi[i]);
    			}
    		  }
    	    }
    	    int ans=0;
    	    for(register int t=1;t<=n;++t){
    		  for(register int k=ans+1;k<=10*t;++k){
    			//cout<<dp[t][k]<<endl;
    			long double l=0,r=T,ll,rr;
    			do{
    			      ll=l+(r-l)/3;
    			      rr=r-(r-l)/3;
    			      if(f(ll)<f(rr)) r=rr;
    			      else l=ll;
    			}while(l+eps<r);
    			if(f(l)+10ll*t<T) ans=max(ans,k);
    		  }
    	    }
    	    cout<<ans<<endl;
          }
          return 0;
    }
    
    
  • 相关阅读:
    Android之基于XMPP即时通讯(转)
    开机启动service小DEMO
    Android 歌词同步滚动效果(转)
    OC中的消息传递和初始化
    oc中对象的初始化
    c语言的结构体字节数统计
    css的页面布局
    说一说我理解的css
    什么是js闭包
    我对js作用域的理解
  • 原文地址:https://www.cnblogs.com/winlere/p/11283919.html
Copyright © 2011-2022 走看看