zoukankan      html  css  js  c++  java
  • 【ybtoj高效进阶 21278】内需消费(线段树)(广义矩阵乘法)(DP)

    内需消费

    题目链接:ybtoj高效进阶 21278

    题目大意

    给你一个数组,然后要你支持两个操作,修改某一个位置的值,或者询问从一个地方走到另一个地方的最大分数。
    分数是你从一个地方沿着数组走,可以选择买入卖出或不变,然后同一时刻只能买入一件东西,资金无限。

    思路

    考虑单个怎么搞,不难想到是 DP,设 (f_{i,0/1}) 表示当前在 (i),身上没有或有东西的分数。
    (f_{i,0}=max{f_{i-1,0},f_{i-1,1}+a_i})
    (f_{i,1}=max{f_{i-1,0}-a_i,f_{i-1,1}})

    发现它只跟前面一个有关,而且似乎可以用矩阵转换?
    当然不是矩阵乘法,我们广义一下,之前是乘了加起来,现在是加了求最大值。

    然后你可以用一个线段树维护一个区间的矩阵,然后每次拎出来一段区间,或者修改一个值的位置就好了。

    代码

    #include<cstdio>
    #include<iostream>
    
    using namespace std;
    
    struct matrix {
    	int n, m;
    	int a[3][3];
    }t[100001 << 2], t_[100001 << 2];
    int n, m, v[100001];
    int op, x, y;
    
    matrix operator *(matrix x, matrix y) {//广义矩阵乘法
    	matrix re;
    	re.n = x.n; re.m = y.m;
    	for (int i = 1; i <= re.n; i++)
    		for (int j = 1; j <= re.m; j++)
    			re.a[i][j] = -2e9;
    	for (int k = 1; k <= x.m; k++)
    		for (int i = 1; i <= re.n; i++)
    			for (int j = 1; j <= re.m; j++)
    				re.a[i][j] = max(re.a[i][j], x.a[i][k] + y.a[k][j]);
    	return re;
    }
    
    void up(int now) {//线段树
    	t[now] = t[now << 1] * t[now << 1 | 1];
    }
    
    void build(int now, int l, int r) {
    	if (l == r) {
    		t[now].n = t[now].m = 2;
    		t[now].a[1][1] = 0; t[now].a[1][2] = -v[l];
    		t[now].a[2][1] = v[l]; t[now].a[2][2] = 0;
    		return ;
    	}
    	int mid = (l + r) >> 1;
    	build(now << 1, l, mid);
    	build(now << 1 | 1, mid + 1, r);
    	up(now);
    }
    
    void change(int now, int l, int r, int pl) {
    	if (l == r) {
    		t[now].n = t[now].m = 2;
    		t[now].a[1][1] = 0; t[now].a[1][2] = -v[l];
    		t[now].a[2][1] = v[l]; t[now].a[2][2] = 0;
    		return ;
    	}
    	int mid = (l + r) >> 1;
    	if (pl <= mid) change(now << 1, l, mid, pl);
    		else change(now << 1 | 1, mid + 1, r, pl);
    	up(now);
    }
    
    matrix query(int now, int l, int r, int L, int R) {
    	if (L <= l && r <= R) return t[now];
    	int mid = (l + r) >> 1;
    	if (L > mid) return query(now << 1 | 1, mid + 1, r, L, R);
    	if (mid >= R) return query(now << 1, l, mid, L, R);
    	return query(now << 1, l, mid, L, R) * query(now << 1 | 1, mid + 1, r, L, R);
    }
    
    void up_(int now) {
    	t_[now] = t_[now << 1] * t_[now << 1 | 1];
    }
    
    void build_(int now, int l, int r) {
    	if (l == r) {
    		t_[now].n = t_[now].m = 2;
    		t_[now].a[1][1] = 0; t_[now].a[1][2] = -v[n - l + 1];
    		t_[now].a[2][1] = v[n - l + 1]; t_[now].a[2][2] = 0;
    		return ;
    	}
    	int mid = (l + r) >> 1;
    	build_(now << 1, l, mid);
    	build_(now << 1 | 1, mid + 1, r);
    	up_(now);
    }
    
    void change_(int now, int l, int r, int pl) {
    	if (l == r) {
    		t_[now].n = t_[now].m = 2;
    		t_[now].a[1][1] = 0; t_[now].a[1][2] = -v[n - l + 1];
    		t_[now].a[2][1] = v[n - l + 1]; t_[now].a[2][2] = 0;
    		return ;
    	}
    	int mid = (l + r) >> 1;
    	if (pl <= mid) change_(now << 1, l, mid, pl);
    		else change_(now << 1 | 1, mid + 1, r, pl);
    	up_(now);
    }
    
    matrix query_(int now, int l, int r, int L, int R) {
    	if (L <= l && r <= R) return t_[now];
    	int mid = (l + r) >> 1;
    	if (L > mid) return query_(now << 1 | 1, mid + 1, r, L, R);
    	if (mid >= R) return query_(now << 1, l, mid, L, R);
    	return query_(now << 1, l, mid, L, R) * query_(now << 1 | 1, mid + 1, r, L, R);
    }
    
    int main() {
    //	freopen("trade.in", "r", stdin);
    //	freopen("trade.out", "w", stdout);
    	
    	scanf("%d %d", &n, &m);
    	for (int i = 1; i <= n; i++) scanf("%d", &v[i]);
    	
    	build(1, 1, n);
    	build_(1, 1, n);
    	while (m--) {
    		scanf("%d", &op);
    		if (op == 1) {
    			scanf("%d %d", &x, &y);
    			if (x <= y)	printf("%d
    ", query(1, 1, n, x, y).a[1][1]);
    				else printf("%d
    ", query_(1, 1, n, n - x + 1, n - y + 1).a[1][1]);
    		}
    		if (op == 2) {
    			scanf("%d %d", &x, &y);
    			v[x] = y;
    			change(1, 1, n, x);
    			change_(1, 1, n, n - x + 1);
    		}
    	}
    	
    	return 0;
    }
    
  • 相关阅读:
    正则表达式体会
    checkbox、全选反选,获取值
    弹出窗体值回调
    页面点击任意js事件,触发360、IE浏览器新页面
    XML增、删、改
    面试题
    行列转换
    DataTable 和Json 字符串互转
    前台js与后台方法互调
    文件与base64二进制转换
  • 原文地址:https://www.cnblogs.com/Sakura-TJH/p/YBTOJ_GXJJ_21278.html
Copyright © 2011-2022 走看看