CodeForces 1093G 、HDU 6435(多维最远曼哈顿距离)


题目链接

https://codeforces.com/contest/1093/problem/G
http://acm.hdu.edu.cn/showproblem.php?pid=6435


解题思路

将K维曼哈顿距离表达式展开:
∑ i = 1 k ∣ a x , i − a y , i ∣ = ∑ i = 1 k c i ( a x , i − a y , i ) = ∑ i = 1 k c i a x , i − ∑ i = 1 k c i a y , i \sum_{i = 1}^{k}\left|a_{x,i} - a_{y,i}\right|=\sum_{i = 1}^{k}c_i(a_{x,i}-a_{y,i})=\sum_{i = 1}^{k}c_ia_{x,i}-\sum_{i = 1}^{k}c_ia_{y,i} i=1kax,iay,i=i=1kci(ax,iay,i)=i=1kciax,ii=1kciay,i
a x , i ≥ a y , i a_{x,i} \ge a_{y,i} ax,iay,i时, c i = 1 c_i = 1 ci=1,否则 c i = − 1 c_i = -1 ci=1
每个点的 c i c_i ci共有 2 k 2^k 2k种状态,可用二进制表示,该位为1,则 c i = 1 c_i = 1 ci=1,否则 c i = − 1 c_i = -1 ci=1
求任意两点的K维最远曼哈顿距离,即可枚举 2 k 2^k 2k种状态,用该状态下最大的 ∑ i = 1 k c i a x , i \sum_{i = 1}^{k}c_ia_{x,i} i=1kciax,i减最小的 ∑ i = 1 k c i a y , i \sum_{i = 1}^{k}c_ia_{y,i} i=1kciay,i来更新答案。
然而这样会出现与事实不符的情况,如当前状态的二进制表示为xxx1x,但最大的 ∑ i = 1 k c i a x , i \sum_{i = 1}^{k}c_ia_{x,i} i=1kciax,i中, a x , 4 = 3 a_{x,4} = 3 ax,4=3,最小的 ∑ i = 1 k c i a y , i \sum_{i = 1}^{k}c_ia_{y,i} i=1kciay,i中, a y , 4 = 5 a_{y,4} = 5 ay,4=5,显然 c 4 = − 1 c_4=-1 c4=1,第四位应该为0。但这种情况下, c 4 a x , 4 − c 4 a y , 4 = − 2 c_4a_{x,4}-c_4a_{y,4}=-2 c4ax,4c4ay,4=2,一定存在xxx0x的状态, c 4 a x , 4 − c 4 a y , 4 = 2 c_4a_{x,4}-c_4a_{y,4}=2 c4ax,4c4ay,4=2,与事实相符且累加后优于xxx1x。

CodeForces 1093G:
1、单点更新
2、区间求K维最远曼哈顿距离
线段树维护每个点的 2 k 2^k 2k种状态,时间复杂度 ( n + q ) 2 k log ⁡ n (n + q)2^k\log n (n+q)2klogn

HDU 6435:
( S x + ∑ i = 1 k c i a x , i ) + ( S y + ∑ i = 1 k ( − c i ) a y , i ) (S_x + \sum_{i = 1}^{k}c_ia_{x,i})+(S_y +\sum_{i = 1}^{k}(-c_i)a_{y,i}) (Sx+i=1kciax,i)+(Sy+i=1k(ci)ay,i)
枚举 2 k 2^k 2k种状态,用该状态下最大的 S x + ∑ i = 1 k c i a x , i S_x + \sum_{i = 1}^{k}c_ia_{x,i} Sx+i=1kciax,i,加按位取反后,最大的 S y + ∑ i = 1 k c i a y , i S_y +\sum_{i = 1}^{k}c_ia_{y,i} Sy+i=1kciay,i来更新答案。


AC代码
//CodeForces 1093G
#include<bits/stdc++.h>
#define SZ(x) (int)(x.size())
using namespace std;

const int MAXN = 200010;

int n, k, q, b[5];

struct STree{
    int ma[32];
    #define lson p << 1
    #define rson p << 1 | 1
    #define ma(x, y) st[x].ma[y]
}st[MAXN << 2];

void upd(int p, int l, int r, int x, int b[]){
    if(l == r){
        for(int i = 0; i < (1 << k); i ++){
            ma(p, i) = 0;
            for(int j = 0; j < k; j ++){
                if((i >> j) & 1)
                    ma(p, i) += b[j];
                else
                    ma(p, i) -= b[j];
            }
        }
        return ;
    }
    int mid = l + r >> 1;
    if(x <= mid)
        upd(lson, l, mid, x, b);
    else
        upd(rson, mid + 1, r, x, b);
    for(int i = 0; i < (1 << k); i ++)
        ma(p, i) = max(ma(lson, i), ma(rson, i));
}

int ask(int p, int l, int r, int ql, int qr, int c){
    if(ql <= l && r <= qr)
        return ma(p, c);
    int mid = l + r >> 1, ans = -1e7;
    if(ql <= mid)
        ans = max(ans, ask(lson, l, mid, ql, qr, c));
    if(qr > mid)
        ans = max(ans, ask(rson, mid + 1, r, ql, qr, c));
    return ans;
}


int main(){
    cin >> n >> k;
    for(int i = 1; i <= n; i ++){
        for(int j = 0; j < k; j ++)
            scanf("%d", b + j);
        upd(1, 1, n, i, b);
    }
    cin >> q;
    while(q --){
        int op, l, r; scanf("%d", &op);
        if(op == 1){
            scanf("%d", &l);
            for(int i = 0; i < k; i ++)
                scanf("%d", b + i);
            upd(1, 1, n, l, b);
        }
        else{
            scanf("%d%d", &l, &r);
            int ans = 0;
            for(int i = 0; i < (1 << k); i ++)
                ans = max(ans, ask(1, 1, n, l, r, i) + ask(1, 1, n, l, r, ((1 << k) - 1) ^ i));
            printf("%d\n", ans);
        }
    }
    return 0;
}
//HDU 6435
#include<bits/stdc++.h>
#define SZ(x) (int)(x.size())
using namespace std;

typedef long long ll;
const int MAXN = 100010;

int n, m, k, a[MAXN][6];
ll ma[32];

int main(){
    int T; cin >> T;
    while(T --){
        cin >> n >> m >> k;
        for(int i = 0; i < (1 << k); i ++)
            ma[i] = -1e12;
        for(int i = 1; i <= n; i ++)
            for(int j = 0; j <= k; j ++)
                scanf("%d", &a[i][j]);
        for(int i = 1; i <= n; i ++){
            for(int t = 0; t < (1 << k); t ++){
                ll cur = a[i][0];
                for(int j = 0; j < k; j ++){
                    if((t >> j) & 1)
                        cur += a[i][j + 1];
                    else
                        cur -= a[i][j + 1];
                }
                ma[t] = max(ma[t], cur);
            }
        }
        ll ans = -1e12;
        for(int i = 1; i <= m; i ++){
            for(int j = 0; j <= k; j ++)
                scanf("%d", &a[i][j]);
            for(int t = 0; t < (1 << k); t ++){
                ll cur = a[i][0];
                for(int j = 0; j < k; j ++){
                    if((t >> j) & 1)
                        cur += a[i][j + 1];
                    else
                        cur -= a[i][j + 1];
                }
                ans = max(ans, cur + ma[((1 << k) - 1) ^ t]);
            }
        }
        cout << ans << '\n';
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值