zoukankan      html  css  js  c++  java
  • Codeforces Round #318(Div. 1) 573 D. Bear and Cavalry【dp+矩阵+线段树优化】

    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 0001 ≤ 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 ≤ nai ≠ 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=maxfi1+aibifi2+aibi1+ai1bifi3+aibi1+ai1bi2+ai2bifi3+aibi2+ai1bi+ai2bi1

    这个转移画画图就可以得到。 
    这样就可以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[n] << endl;
    	}
    	return 0;
    }
    

    但是有更高效的做法 

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

    那么

    fi,0=maxfi1,0+aibifi1,1+aibi1+ai1bifi1,2+aibi1+ai1bi2+ai2bifi1,2+aibi2+ai1bi+ai2bi1

    fi,1=fi1,0

    fi,2=fi1,1

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

    aibiaibi1+ai1bimax{aibi1+ai1bi2+ai2biaibi2+ai1bi+ai2bi1}0infinfinf0inf

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

    (未完待续)


    Fighting~
  • 相关阅读:
    DML、DDL、DCL的区别
    exe文件图标不见了,教你win10桌面EXE文件图标不见了如何解决
    js获取近十二个月
    关于tomcat中的三个端口的作用及其相关细节
    js判断对象是否为空对象的几种方法
    解决myeclipse validation验证javascript导致速度变慢的现象
    jQuery基础教程之is()方法和has() 方法
    2015年6月发布了ECMAScript6版本
    http系列--从输入 URL 到页面加载完成的过程
    一篇文看懂Hadoop
  • 原文地址:https://www.cnblogs.com/Archger/p/8451601.html
Copyright © 2011-2022 走看看