2021杭电多校第三场 1009——Rise in Price

3 篇文章 0 订阅
3 篇文章 0 订阅

题目大意

给你一个 n × n n \times n n×n 的矩阵,每个点有两个值,代表当前点物品的累加的数量和累加的价值,累加的价值就是说你到达了这个点,你所有物品的价值都会累加上这个价值,累加的数量表示你到达了这个点你的物品数量会加上这个值,你每次只能向下或者向右走。问你从 ( 1 , 1 ) (1, 1) (1,1) 走到 ( n , n ) (n, n) (n,n) 所获得的总价值最大是多少,总价值为数量乘以价值。
1 ≤ n ≤ 100 1 \leq n \leq 100 1n100

解题思路

d p dp dp
由于每个点有两个状态,我们将每个点的状态用一个 v e c t o r vector vector 存起来。
d p [ i ] [ j ] = d p [ i − 1 ] [ j ] + d p [ i ] [ j − 1 ] dp[i][j] = dp[i-1][j] + dp[i][j-1] dp[i][j]=dp[i1][j]+dp[i][j1]
此时,走到 i , j i, j i,j 位置的答案就是 d p [ i ] [ j ] dp[i][j] dp[i][j] 里面每个点的二维乘积
但是这样的复杂度是 O ( T × 2 n − 1 ) O(T \times 2^{n-1}) O(T×2n1)
我们发现有一些状态是必不可能成为答案的,我们需要将这些状态给即使排除。比如 f i i ≤ f i j   & &   s e i ≤ s e j fi_i \leq fi_j \ \&\& \ se_i \leq se_j fiifij && seisej
那么, i i i 这个点永远没有 j j j 这个点优,所以我们要即使排除这个状态,以减少复杂度。
每次我们在合并的时候归并一下,把每个点的 v e c t o r vector vector 当做一个单调栈,当出现上述情况时及时排除不可能的答案。

Code

#include <bits/stdc++.h>
#define ll long long
#define qc ios::sync_with_stdio(false); cin.tie(0);cout.tie(0)
#define fi first
#define se second
#define PII pair<int, int>
#define PLL pair<ll, ll>
#define pb push_back
using namespace std;
const int MAXN = 2e5 + 7;
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
const ll mod = 1e9 + 7;
inline int read()
{
    int x=0,f=1;char ch=getchar();
    while (!isdigit(ch)){if (ch=='-') f=-1;ch=getchar();}
    while (isdigit(ch)){x=x*10+ch-48;ch=getchar();}
    return x*f;
}
int n;
ll a[107][107];
ll b[107][107];
vector<PLL> v[107][107];
void solve(){
	cin >> n;
	for(int i = 1; i <= n; i++){
		for(int j = 1; j <= n; j++){
			cin >> a[i][j];
		}
	}
	for (int i = 1; i <= n; ++i){
	    for (int j = 1; j <= n; ++j){
	        cin >> b[i][j];
	    }
	}
	for (int i = 1; i <= n; ++i){
	    for (int j = 1; j <= n; ++j){
			if(i == 1 && j == 1){
				v[i][j].pb({a[i][j], b[i][j]});
				continue;
			}
	        ll num = a[i][j];
			ll add = b[i][j];
			int p1 = 0;
			int sz1 = v[i-1][j].size();
			int p2 = 0;
			int sz2 = v[i][j-1].size();
			int cnt = -1;
			while(p1 < sz1 && p2 < sz2){
				int f1 = v[i-1][j][p1].fi;
				int s1 = v[i-1][j][p1].se;
				int f2 = v[i][j-1][p2].fi;
				int s2 = v[i][j-1][p2].se;
				if(f1 <= f2){
					while(cnt != -1 && v[i][j][cnt].fi <= f1 + num && v[i][j][cnt].se <= s1 + add){
						cnt--;
						v[i][j].pop_back();
					}
					v[i][j].pb({f1 + num, s1 + add});
					cnt++;
					p1++;
				}
				else{
					while(cnt != -1 && v[i][j][cnt].fi <= f2 + num && v[i][j][cnt].se <= s2 + add){
						cnt--;
						v[i][j].pop_back();
					}
					cnt++;
					v[i][j].pb({f2 + num, s2 + add});
					p2++;
				}
			}
			while(p1 < sz1){
				int f1 = v[i-1][j][p1].fi;
				int s1 = v[i-1][j][p1].se;
				while(cnt != -1 && v[i][j][cnt].fi <= f1 + num && v[i][j][cnt].se <= s1 + add){
					cnt--;
					v[i][j].pop_back();
				}
				v[i][j].pb({f1 + num, s1 + add});
				cnt++;
				p1++;
			}
			while(p2 < sz2){
				int f2 = v[i][j-1][p2].fi;
				int s2 = v[i][j-1][p2].se;
				while(cnt != -1 && v[i][j][cnt].fi <= f2 + num && v[i][j][cnt].se <= s2 + add){
					cnt--;
					v[i][j].pop_back();
				}
				cnt++;
				v[i][j].pb({f2 + num, s2 + add});
				p2++;
			}
	    }
	}
	ll ans = 0;
	for(auto [x, y] : v[n][n]){
		ans = max(ans, x * y);
	}
	cout << ans << "\n";
	for (int i = 1; i <= n; ++i){
	    for (int j = 1; j <= n; ++j){
	        v[i][j].clear();
	    }
	}
}

int main()
{
    #ifdef ONLINE_JUDGE
    #else
       freopen("in.txt", "r", stdin);
       freopen("out.txt", "w", stdout);
    #endif

    qc;
    int T;
    cin >> T;
    // T = 1;
    while(T--){

        solve();
    }
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值