codeforces 318 D. Bear and Cavalry


题目描述:

D. Bear and Cavalry

time limit per test:3 seconds

memory limit per test:256 megabytes

input:standard input

output:standard output

Would you want to fight against bears riding horses? Me neither.

Limak is a grizzly bear. He is general of the dreadful army of Bearland. The most important part of an army is cavalry of course.

Cavalry of Bearland consists of n warriors and n horses. i-th warrior has strength wi and i-th horse has strength hi. Warrior together with his horse is called a unit. Strength of a unit is equal to multiplied strengths of warrior and horse. Total strength of cavalry is equal to sum of strengths of all n units. Good assignment of warriors and horses makes cavalry truly powerful.

Initially, i-th warrior has i-th horse. You are given q queries. In each query two warriors swap their horses with each other.

General Limak must be ready for every possible situation. What if warriors weren’t allowed to ride their own horses? After each query find the maximum possible strength of cavalry if we consider assignments of all warriors to all horses that no warrior is assigned to his own horse (it can be proven that for n ≥ 2 there is always at least one correct assignment).

Note that we can’t leave a warrior without a horse.

Input

The first line contains two space-separated integers, n and q (2 ≤ n ≤ 30 000, 1 ≤ q ≤ 10 000).

The second line contains n space-separated integers, w1, w2, …, wn (1 ≤ wi ≤ 106) — strengths of warriors.

The third line contains n space-separated integers, h1, h2, …, hn (1 ≤ hi ≤ 106) — strengths of horses.

Next q lines describe queries. i-th of them contains two space-separated integers ai and bi (1 ≤ ai, bi ≤ n, ai ≠ bi), indices of warriors who swap their horses with each other.

Output

Print q lines with answers to queries. In i-th line print the maximum possible strength of cavalry after first i queries.

题解:

好题。首先是一个贪心性质:我们从大到小排序,如果没有限制,那么肯定是按照顺序来配对是结果最大的。但是现在有一些限制的关系。那么怎么办呢?我们探索一下。我们设dp【i】,表示i是最后一个,解决完dp【i】的值。那么推i:如果wi可以和hi匹配,那么我们直接让wi和hi匹配就是最好的。如果wi和hi不可以,那么我们让wi-1和hi以及wi和hi-1来匹配,这样一定是最好的。但是有一个问题,可能wi-2和hi-2不能匹配,所以可能i会涉及到i-2. 但是有一个重要的性质,我们发现i最多只会涉及到i-2,再往前就一定可以通过调整来不那么远。 那么我们最裸的dp就是:dp【i】,然后o(3)的暴力转移。
但是这道题目可以用线段树来加速。毕竟每一次询问只改了很少的值。主要想明白两端区间怎么合并,就是怎么pushUp。怎么才能合并呢?dp的向前延伸和向后延伸都是2.l mid mid+1 r 这两个怎么合并?看mid+1最多会受到前面多少的影响.mid,mid-1. 那么暴力枚举mid+1和哪3(也可能是2或者自己)个发生关系。所以我们只需要把l到mid的后面的2个元素可能性的去掉多维护一些东西就行了。 我们维护一个3*3的矩阵。 0、1、2分别代表去掉前、后0.1.2个元素之后的dp值。这样在合并的时候只需要大约3*3*3的暴力合并就行了。
有一个特殊的地方就是:当区间长度小于4的时候会比较麻烦,因此我们区间小于8之后就不再分,而是改用暴力。

重点:

(1)贪心的想乘
(2)有条件限制的时候不用直接想,可以转成dp简化思维
(3)发现性质,i只会最多和i-2发生关系
(4)每次只修改一点,并且dp的后效性很小,可以用线段树加速

代码:
#pragma comment(linker, "/STACK:102400000,102400000")
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <cmath>
#include <ctype.h>
#include <limits.h>
#include <cstdlib>
#include <algorithm>
#include <vector>
#include <queue>
#include <map>
#include <stack>
#include <set>
#include <bitset>
#define CLR(a) memset(a, 0, sizeof(a))
#define REP(i, a, b) for(ll i = a;i < b;i++)
#define REP_D(i, a, b) for(ll i = a;i <= b;i++)

typedef long long ll;

using namespace std;

const ll maxn = 30000+100;
const ll MAX_NODE = maxn*4 + 10;

ll n, q;

struct info
{
    ll no, s, wno;
    info(ll _no = 0, ll _s = 0, ll _wno = 0)
    {
        no = _no;
        s = _s;
        wno = _wno;
    }
};
info h[maxn], w[maxn];
ll posH[maxn], posW[maxn];
ll f[maxn];
ll tree[MAX_NODE][3][3];

ll dp(ll l, ll r)
{
    f[l-1] = 0;
    for(ll i = l; i<=r; i++)
        f[i] = -1;
    for(ll i = l; i<=r; i++)
    {
        ll j = i;
        if(j>=l&&f[j-1]!=-1&&w[i].no!=h[j].no)
        {
            f[i] =max(f[i], f[j-1]+(ll)w[i].s*(ll)h[j].s);
        }
        j--;
        if(j>=l&&f[j-1]!=-1)
        {
            if(w[i].no!=h[j].no&&w[j].no!=h[i].no)
                f[i] = max(f[i], f[j-1]+(ll)w[i].s*(ll)h[j].s+(ll)w[j].s*(ll)h[i].s);
        }
        j--;
        if(j>=l&&f[j-1]!=-1)
        {
            if(w[j].no!=h[j+1].no&&w[j+1].no!=h[j+2].no&&w[i].no!=h[j].no)
                f[i] = max(f[i], f[j-1]+(ll)w[j].s*(ll)h[j+1].s+(ll)w[j+1].s*(ll)h[j+2].s+(ll)w[i].s*(ll)h[j].s);
            if(w[j].no!=h[i].no&&w[j+1].no!=h[j].no&&w[i].no!=h[j+1].no)
                f[i] = max(f[i], f[j-1]+(ll)w[j].s*(ll)h[i].s+(ll)w[j+1].s*(ll)h[j].s+(ll)w[i].s*(ll)h[j+1].s);
        }
    }
    return f[r];
}
void pushUp(ll rt, ll l, ll r)//下面的都已经好了.且一定有下面的
{
    ll mid = ((l + r)>>1), lRt = (rt<<1), rRt = ((rt<<1)|1);
    if(mid-l+1<4||r-mid<4)
    {
        for(ll i = 0; i<=2; i++)
        {
            for(ll j = 0; j<=2; j++)
            {
                ll tmp = dp(l+i, r-j);
                tree[rt][i][j] = tmp;
            }
        }
    }
    else
    {
        for(ll i = 0; i<=2; i++)
            for(ll j = 0; j<=2; j++)
                tree[rt][i][j]=-1;
        for(ll xa = 0; xa<=2; xa++)
        {
            for(ll ya = 0; ya<=2; ya++)
            {
                if(tree[lRt][xa][ya]!=-1)
                {
                    for(ll xb=0; xb+ya<=3&&xb<=2; xb++)
                    {
                        for(ll yb = 0; yb<=2; yb++)
                        {
                            if(tree[rRt][xb][yb]!=-1)
                            {
                                ll &key = tree[rt][xa][yb];
                                ll a = tree[lRt][xa][ya], b = tree[rRt][xb][yb];
                                if(ya==0&&xb==0)
                                    key = max(key, a+b);
                                if(ya==0||xb==0)
                                    continue;
                                if(ya==1&&xb==1)
                                {
                                    if(w[mid].no!=h[mid+1].no&&w[mid+1].no!=h[mid].no)
                                        key = max(key, a+b+(ll)w[mid].s*(ll)h[mid+1].s+(ll)w[mid+1].s*(ll)h[mid].s);
                                }
                                if((ya==1&&xb==2)||(ya==2&&xb==1))
                                {
                                    ll i = mid - ya+1;
                                    ll j = i+1;
                                    ll k = j+1;
                                    if(w[i].no!=h[j].no&&w[j].no!=w[k].no&&w[k].no!=h[i].no)
                                        key = max(key, a+b+(ll)w[i].s*(ll)h[j].s+(ll)w[j].s*(ll)h[k].s+(ll)w[k].s*(ll)h[i].s);
                                    if(w[i].no!=w[k].no&&w[j].no!=h[i].no&&w[k].no!=h[j].no)
                                        key = max(key, a+b+(ll)w[i].s*(ll)h[k].s+(ll)w[j].s*(ll)h[i].s+(ll)w[k].s*(ll)h[j].s);
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}

void dfs(ll rt, ll l, ll r)
{
    if(r-l+1 < 4)
        return;
    ll mid = ((l + r)>>1), lRt = (rt<<1), rRt = ((rt<<1)|1);
    dfs(lRt, l, mid);
    dfs(rRt, mid+1, r);
    pushUp(rt, l, r);
}
void initail()
{
    dfs(1, 1, n);
}

void change(ll a, ll b, ll c, ll d, ll rt, ll l, ll r)
{
    if(r - l + 1< 4)
        return;
    ll mid = ((l + r)>>1), lRt = (rt<<1), rRt = ((rt<<1)|1);
    if((a>=l&&a<=mid)||(b>=l&&b<=mid)||(c>=l&&c<=mid)||(d>=l&&d<=mid))
    {
        change(a, b, c, d, lRt, l, mid);
    }
    if((a>=mid+1&&a<=r)||(b>=mid+1&&b<=r)||(c>=mid+1&&c<=r)||(d>=mid+1&&d<=r))
    {
        change(a, b, c, d, rRt, mid + 1, r);
    }
    pushUp(rt, l, r);//向上push
}

void solve()
{
    initail();
    while(q--)
    {
        ll a, b;
        scanf("%I64d%I64d", &a, &b);
        swap(w[posW[a]].no, w[posW[b]].no);
        if(n>=4)
        {
            change(posW[a], posW[b], posH[w[posW[a]].no], posH[w[posW[b]].no], 1, 1, n);
            printf("%I64d\n", tree[1][0][0]);
        else
        {
            printf("%I64d\n", dp(1, n));
        }
    }
}

bool cmp(info a, info b)
{
    return a.s < b.s;
}
int main()
{
    freopen("4Din.txt", "r", stdin);
    //freopen("4Dout.txt", "w", stdout);
    while(scanf("%I64d%I64d", &n, &q)!=EOF)
    {
        for(ll i = 1; i<=n; i++)
        {
            scanf("%I64d", &w[i].s);
            w[i].no = i;
            w[i].wno = i;
        }
        for(ll i = 1; i<=n; i++)
        {
            scanf("%I64d", &h[i].s);
            h[i].no = i;
        }
        sort(w+1, w+1+n, cmp);
        sort(h+1, h+1+n, cmp);
        for(ll i = 1; i<=n; i++)
        {
            posW[w[i].wno] = i;
            posH[h[i].no] = i;
        }
        solve();
    }
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值