題目描述:
D. Bear and Cavalryios
time limit per test:3 secondsc++
memory limit per test:256 megabytesweb
input:standard inputide
output:standard outputsvg
Would you want to fight against bears riding horses? Me neither.spa
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..net
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.code
Initially, i-th warrior has i-th horse. You are given q queries. In each query two warriors swap their horses with each other.regexp
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).xml
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、一、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;
}
本文分享 CSDN - ruclion。
若有侵權,請聯繫 support@oschina.cn 刪除。
本文參與「OSC源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。