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~
  • 相关阅读:
    Devrama Slider
    全栈开发必备的10款 Sublime Text 插件
    经典网页设计:使用颜色滤镜效果的20个网站
    Nibbler – 免费的网站测试和指标评分工具
    使用 HTML5 Canvas 绘制出惊艳的水滴效果
    Qt4 和 Qt5 模块的分类
    设计Qt风格的C++API
    Qt属性系统
    Qt实现艺术字效果
    Qt中容器类应该如何存储对象(最好使用对象指针类型,如:QList<TestObj*>,而不要使用 QList<TestObj> 这样的定义,建议采用 智能指针QSharedPointer)
  • 原文地址:https://www.cnblogs.com/Archger/p/8451601.html
Copyright © 2011-2022 走看看