您的位置:首页 > 其它

Codeforces Round #318(Div. 1) 573 D. Bear and Cavalry【dp+矩阵+线段树优化】

2017-08-09 19:41 357 查看
D. Bear and Cavalry

23ff7
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.

Examples

input
4 2
1 10 100 1000
3 7 2 5
2 4
2 4


output
5732
7532


input
3 3
7 11 5
3 2 1
1 2
1 3
2 3


output
44
48
52


input
7 4
1 2 4 8 16 32 64
87 40 77 29 50 11 18
1 5
2 7
6 2
5 6


output
9315
9308
9315
9315


Note

Clarification for the first sample:
Warriors: 1 10 100 1000

Horses: 3 7 2 5

After first query situation looks like the following:
Warriors: 1 10 100 1000

Horses: 3 5 2 7

We can get 1·2 + 10·3 + 100·7 + 1000·5 = 5732 (note that no hussar takes his own horse in this assignment).

After second query we get back to initial situation and optimal assignment is 1·2 + 10·3 + 100·5 + 1000·7 = 7532.

Clarification for the second sample. After first query:
Warriors: 7 11 5

Horses: 2 3 1

Optimal assignment is 7·1 + 11·2 + 5·3 = 44.

Then after second query 7·3 + 11·2 + 5·1 = 48.

Finally 7·2 + 11·3 + 5·1 = 52.

题意:给出n个战士和他们各自的n批马,我们可以把马换给别的战士,但是都得换(即战士不能拥有原来的马),我们要每个战士乘以给他换的那个马的和最大。q次询问,每次把2个战士的马交换,输出和最大的答案。

思路:首先如果没有限制,那么根据排序不等式,肯定按顺序匹配战士和马最好。但是现在有了战士不能和自己的马匹配的限制。

于是就有了一个重要的性质:最优匹配的前提下,排序后第i号战士只会与[i-2,i+2]号马匹配

(证明:

设有一种情况i对应i+3

i—–(i+3)

i+1—(i+2)

i+2—(i)

i+3—(i+1)

那么,对于i,i+1来说,必定在(i–i+2),(i+1–i+3)中有一个限制必选,否则交换i,i+1更优

同理,(i–i)(i+2–i+3),(i–i+1)(i+3–i+3)中有一个限制比选

发现与限制是一组排列不符,而且i对应i+2时只有(i-i+2)(i+1-i)(i+2-i+1)这种可能



于是就可以DP了,



fi表示前i个点匹配的答案。

那么

fi=max⎧⎩⎨⎪⎪⎪⎪⎪⎪⎪⎪fi−1+ai∗bifi−2+ai∗bi−1+ai−1∗bifi−3+ai∗bi−1+ai−1∗bi−2+ai−2∗bifi−3+ai∗bi−2+ai−1∗bi+ai−2∗bi−1

这个转移画画图就可以得到。

这样就可以O(n2),稍微常数优化一下就可以过。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>
#include <string>
#include <map>
#include <cstring>
#define INF 0x3f3f3f3f
#define ms(x,y) memset(x,y,sizeof(x))
using namespace std;

typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> P;

const int maxn = 30010;
const int mod = 998244353;

#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1

struct node {
ll v;
int id;
};

bool cmp(node a, node b)
{
return a.v < b.v;
}

int posa[maxn], posb[maxn], ban[maxn];
ll w1[maxn], w2[maxn], w3[maxn], f[maxn];
node a[maxn], b[maxn];

void cal(int i)
{
w1[i] = w2[i] = w3[i] = -INF;
ll t1 = -INF, t2 = -INF;
if (i >= 1 && ban[i] != i) w1[i] = a[i].v*b[i].v;
if (i >= 2 && ban[i] != i - 1 && ban[i - 1] != i) w2[i] = a[i].v*b[i - 1].v + a[i - 1].v*b[i].v;
if (i >= 3 && ban[i] != i - 2 && ban[i - 1] != i&&ban[i - 2] != i - 1) t1 = a[i].v*b[i - 2].v + a[i - 1].v*b[i].v + a[i - 2].v*b[i - 1].v;
if (i >= 3 && ban[i] != i - 1 && ban[i - 1] != i - 2 && ban[i - 2] != i) t2 = a[i].v*b[i - 1].v + a[i - 1].v*b[i - 2].v + a[i - 2].v*b[i].v;
w3[i] = max(t1, t2);
}

int main()
{
int n, q;
cin >> n >> q;
for (int i = 1; i <= n; i++)
{
cin >> a[i].v;
a[i].id = i;
}
for (int i = 1; i <= n; i++)
{
cin >> b[i].v;
b[i].id = i;
}
sort(a + 1, a + n + 1, cmp);
sort(b + 1, b + n + 1, cmp);
for (int i = 1; i <= n; i++)
{
posa[a[i].id] = i;
posb[b[i].id] = i;
}
for (int i = 1; i <= n; i++)
{
ban[i] = posb[a[i].id];
}
for (int i = 1; i <= n; i++)
{
cal(i);
}
for (int k = 0; k < q; k++)
{
int x, y;
cin >> x >> y;
x = posa[x], y = posa[y];
swap(ban[x], ban[y]);
for (int i = max(1, x - 5); i <= min(n, x + 5); i++) cal(i);
for (int i = max(1, y - 5); i <= min(n, y + 5); i++) cal(i);
f[0] = 0;
for (int i = 1; i <= n; i++)
{
f[i] = f[i - 1] + w1[i];
if (i >= 2) f[i] = max(f[i], f[i - 2] + w2[i]);
if (i >= 3) f[i] = max(f[i], f[i - 3] + w3[i]);
}
cout << f
<< endl;
}
return 0;
}


但是有更高效的做法

令fi,j表示前i个,前i-j个已经被匹配了的答案

那么

fi,0=max⎧⎩⎨⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪fi−1,0+ai∗bifi−1,1+ai∗bi−1+ai−1∗bifi−1,2+ai∗bi−1+ai−1∗bi−2+ai−2∗bifi−1,2+ai∗bi−2+ai−1∗bi+ai−2∗bi−1

fi,1=fi−1,0

fi,2=fi−1,1

这个转移可以被描述成矩阵

⎡⎣⎢⎢⎢ai∗biai∗bi−1+ai−1∗bimax{ai∗bi−1+ai−1∗bi−2+ai−2∗biai∗bi−2+ai−1∗bi+ai−2∗bi−1}0−inf−inf−inf0−inf⎤⎦⎥⎥⎥

因为矩乘满足结合律,所以可以用线段树维护

(未完待续)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: