CodeForces 1107 F Vasya and Endless Credits

题目传送门

题解:

需要注意到的是 每个offer都获益都是会随着时间的增加而渐少(或不变)。

所以我们可以知道,最多在第n个月的时候这个人会买车离开。

 

solve1:最优2分图匹配

我们可以把每个月都和每个offer建边。

val[i][j]代表的是离开前倒数第i个月获取了第j个月的offer, 所以边权就是 max(0ll, a-min(j-1,k)*b).

最后跑一遍km。

所以复杂度是 n^3.

代码:

 1 /*
 2 code by: zstu wxk
 3 time: 2019/02/02
 4 */
 5 #include<bits/stdc++.h>
 6 using namespace std;
 7 #define Fopen freopen("_in.txt","r",stdin); freopen("_out.txt","w",stdout);
 8 #define LL long long
 9 #define ULL unsigned LL
10 #define fi first
11 #define se second
12 #define pb push_back
13 #define lson l,m,rt<<1
14 #define rson m+1,r,rt<<1|1
15 #define lch(x) tr[x].son[0]
16 #define rch(x) tr[x].son[1]
17 #define max3(a,b,c) max(a,max(b,c))
18 #define min3(a,b,c) min(a,min(b,c))
19 typedef pair<int,int> pll;
20 const int inf = 0x3f3f3f3f;
21 const int _inf = 0xc0c0c0c0;
22 const LL INF = 0x3f3f3f3f3f3f3f3f;
23 const LL _INF = 0xc0c0c0c0c0c0c0c0;
24 const LL mod =  (int)1e9+7;
25 const int N = 510;
26 int n;
27 LL val[N][N];
28 LL lx[N], ly[N], slack[N];
29 int linky[N];
30 LL pre[N];
31 bool vis[N], visx[N], visy[N];
32 void bfs(int k){
33     LL px, py = 0,yy = 0, d;
34     memset(pre, 0, sizeof(LL) * (n+2));
35     memset(slack, inf, sizeof(LL) * (n+2));
36     linky[py]=k;
37     do{
38         px = linky[py],d = INF, vis[py] = 1;
39         for(int i = 1; i <= n; i++)
40             if(!vis[i]){
41                 if(slack[i] > lx[px] + ly[i] - val[px][i])
42                     slack[i] = lx[px] + ly[i] -val[px][i], pre[i]=py;
43                 if(slack[i]<d) d=slack[i],yy=i;
44             }
45         for(int i = 0; i <= n; i++)
46             if(vis[i]) lx[linky[i]] -= d, ly[i] += d;
47             else slack[i] -= d;
48         py = yy;
49     }while(linky[py]);
50     while(py) linky[py] = linky[pre[py]] , py=pre[py];
51 }
52 void KM(){
53     memset(lx, 0, sizeof lx);
54     memset(ly, 0, sizeof ly);
55     memset(linky, 0, sizeof(int)*(n+2));
56     for(int i = 1; i <= n; i++)
57         memset(vis, 0, sizeof(bool)*(n+2)), bfs(i);
58 }
59 void input(){
60     scanf("%d", &n);
61     LL a, b, k;
62     for(int i = 1; i <= n; ++i){
63         scanf("%I64d%I64d%I64d", &a, &b, &k);
64         for(LL j = 0; j < n; ++j){
65             val[i][j+1] = max(0ll, a-min(j,k)*b);
66         }
67     }
68 }
69 int main(){
70     input();
71     KM();
72     LL ans = 0;
73     for(int i = 1; i <= n; ++i)
74         ans += lx[i] + ly[i];
75     printf("%lld\n", ans);
76     return 0;
77 }
View Code

 

 

solve2:DP

首先需要明白一点,就是如果所有offer 还款的期限还没有到的话,那么肯定是bi越大的offer越后拿更优。

所以把所有的offer按bi大小sort一下,大的排在前面。

dp[i][j] 代表的是 处理到第i个物品, 倒数第j个月的花费是多少。

所以,最显然的转移方式就是 dp[i][j] = max(dp[i][j], dp[i-1][j-1] + max(0ll, A[i].a - (j-1)*A[i].b)).

还需要明白的一点就是,如果bi越大,理论上是放在越后拿越好,但是到如果完全还完贷款的那种offer,是越早拿越好,可以让别的offer少还一个月的贷款。

所以又存在另一种转移方式 dp[i][j] = dp[i-1][j] + max(0ll, A[i].a - A[i].k*A[i].b);

代码:

/*
code by: zstu wxk
time: 2019/02/02
*/
#include<bits/stdc++.h>
using namespace std;
#define Fopen freopen("_in.txt","r",stdin); freopen("_out.txt","w",stdout);
#define LL long long
#define ULL unsigned LL
#define fi first
#define se second
#define pb push_back
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define lch(x) tr[x].son[0]
#define rch(x) tr[x].son[1]
#define max3(a,b,c) max(a,max(b,c))
#define min3(a,b,c) min(a,min(b,c))
typedef pair<int,int> pll;
const int inf = 0x3f3f3f3f;
const int _inf = 0xc0c0c0c0;
const LL INF = 0x3f3f3f3f3f3f3f3f;
const LL _INF = 0xc0c0c0c0c0c0c0c0;
const LL mod =  (int)1e9+7;
const int N = 550;
struct Node{
    LL a, b, k;
    bool operator<(const Node & x) const{
        return b > x.b;
    }
}A[N];
int n;
LL dp[N][N];
void Ac(){
    for(int i = 1; i <= n; ++i)
        scanf("%I64d%I64d%I64d", &A[i].a, &A[i].b, &A[i].k);
    sort(A+1, A+1+n);
    for(int i = 1; i <= n; ++i){
        for(int j = 0; j <= n; ++j){
            dp[i][j] = dp[i-1][j] + max(0ll, A[i].a - A[i].k*A[i].b);
            if(j) dp[i][j] = max(dp[i][j], dp[i-1][j-1] + max(0ll, A[i].a - (j-1)*A[i].b));
        }
    }
    LL ans = 0;
    for(int i = 0; i <= n; ++i)
        ans = max(ans, dp[n][i]);
    printf("%I64d\n", ans);
}
int main(){
    while(~scanf("%d", &n)){
        Ac();
    }
    return 0;
}
View Code

 

转载于:https://www.cnblogs.com/MingSD/p/10349136.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值