洛谷 P2647 最大收益
阿新 • • 發佈:2018-07-09
ostream read == git 疊加 ref () tle char 動規
我是題面
恩,貪心,鑒定完畢。
一個物品是否放進來,取決於它是否能對答案做出貢獻。
那物品i的貢獻就是\(w[i]-r[i]\)
可是收益的減少是會疊加的
那就是\(w[i]-j*r[i]\),j表示選擇物品i後又選擇的物品數量
可是我怎麽知道選擇i後又會選擇幾件物品啊
那麽我們引入一個新的值\(d[i]=w[i]/r[i]\),表示若使物品i對答案有貢獻,選擇物品i後最多再選擇d件物品
既然這樣,我們也有點眉目了,dfs啊
很好,寫的很漂亮,50。。。TLE
dfs
看來是不能再優化了
那讓我們退回去,往前看“可是我怎麽知道選擇i後又會選擇幾種物品啊”
好像有一種方法可以知道還會再選幾件,沒錯,你是不是也想到了,就是 dfs
我們用\(f[i][j]\)表示在前i種物品中選擇j件,可是這怎麽記憶之前所說的j呢?
還記得之前說好的貪心嗎,這裏繼續貪。
我們把物品按照r從大到小的順序排序,\(f[i][j]\)表示i件物品選擇j件且最先選擇j件時的收益
這裏的貪心很好證明,既然r要取多次,那麽我們自然默認讓更小的r選擇更多的次數
下面是代碼
dfs版
#include<algorithm> #include<iostream> #include<cstring> #include<cstdio> #include<cctype> #define ll long long #define gc() getchar() #define maxn 3005 using namespace std; inline ll read(){ ll a=0;int f=0;char p=gc(); while(!isdigit(p)){f|=p=='-';p=gc();} while(isdigit(p)){a=(a<<3)+(a<<1)+(p^48);p=gc();} return f?-a:a; } void write(ll a){ if(a>9)write(a/10); putchar(a%10+'0'); } int n; struct ahaha{ int w,r,d; friend bool operator < (ahaha x,ahaha y){ return x.d>y.d; } }a[maxn]; bool c[maxn]; //表示物品是否被選擇過 int ans; inline int max(int x,int y){return x>y?x:y;} inline int min(int x,int y){return x<y?x:y;} void dfs(int sum,int sr,int sy){ //sum表示當前收益,sr表示需要累計下去的r,sy表示最多還能選擇sy個數貪心就不優了 ans=max(ans,sum); //因為不知道選多少個數,所以ans每步比較 if(!sy)return; //如果不能再選 返回 for(int i=1;i<=n;++i){ if(c[i])continue; c[i]=1; dfs(sum+a[i].w-sr,sr+a[i].r,min(sy-1,a[i].d)); //sy應取最小值 c[i]=0; } } inline void solve(){ for(int i=1;i<=n;++i){ c[i]=1; dfs(a[i].w,a[i].r,a[i].d); c[i]=0; } } int main(){ n=read(); for(int i=1;i<=n;++i)a[i].w=read(),a[i].r=read(),a[i].d=a[i].w/a[i].r; sort(a+1,a+n+1); solve(); write(ans); return 0; }
DP版
#include<algorithm> #include<iostream> #include<cstring> #include<cstdio> #include<cctype> #define ll long long #define gc() getchar() #define maxn 3005 using namespace std; inline ll read(){ ll a=0;int f=0;char p=gc(); while(!isdigit(p)){f|=p=='-';p=gc();} while(isdigit(p)){a=(a<<3)+(a<<1)+(p^48);p=gc();} return f?-a:a; } void write(ll a){ if(a>9)write(a/10); putchar(a%10+'0'); } int n,f[maxn][maxn],ans; struct ahaha{ int w,r; friend bool operator < (ahaha x,ahaha y){ return x.r>y.r; } }a[maxn]; int main(){ n=read(); for(int i=1;i<=n;++i)a[i].w=read(),a[i].r=read(); sort(a+1,a+n+1); f[1][1]=a[1].w; for(int i=2;i<=n;++i) for(int j=1;j<=i;++j) f[i][j]=max(f[i-1][j],f[i-1][j-1]+a[i].w-a[i].r*(j-1)); //表示選擇i個物品時,選擇物品i和不選物品i兩種操作 for(int i=1;i<=n;++i)ans=max(ans,f[n][i]); write(ans); return 0; }
洛谷 P2647 最大收益