1. 程式人生 > >Luogu4131 WC2005 友好的生物 狀壓DP

Luogu4131 WC2005 友好的生物 狀壓DP

傳送門


 

首先$C_i$是沒有意義的,因為可以直接讓$d_i \times= C_i$,答案也是一樣的

所以我們現在考慮求$(\sum_{i=1}^{K-1} |d_{p,i}-d_{q,i}|) - |d_{p,K} - d_{q,K}|$的最大值

這個絕對值好煩人啊qaq

我們考慮如何消去這個絕對值

先拋開第$K$項,假設我們要計算$\sum_{i=1}^{K-1} |d_{p,i}-d_{q,i}|$的最大值

可以發現$\sum_{i=1}^{K-1} |d_{p,i}-d_{q,i}| = max(\sum_{i=1}^{K-1} (d_{p,i}-d_{q,i}) \times (-1)^{a_i})=max(\sum_{i=1}^{K-1} d_{p,i} \times (-1)^{a_i} + d_{q,i} \times (-1)^{a_i + 1})$

其中$0 \leq a_i \leq 1$且取遍所有情況

那麼我們可以設$dp_j$表示$a_i$狀壓成二進位制表示為$j$時的$\sum_{i=1}^{K-1} d_{p,i} \times (-1)^{a_i}$的最大值,$ind_j$表示$dp_j$取到最大值時的$p$值,轉移也比較方便了。

最後我們考慮第$K$維的影響,我們不妨按照第$K$維從小到大排序,那麼$dp_j$表示$a_i$狀壓成二進位制表示為$j$時的$\sum_{i=1}^{K-1} d_{p,i} \times (-1)^{a_i} + d_{K,i}$的最大值,最後統計答案時再減去當前的$d_K$值就可以了

 

 1 #include<bits/stdc++.h>
 2 //This code is written by Itst
 3 using namespace std;
 4 
 5 inline int read(){
 6     int a = 0;
 7     char c = getchar();
 8     bool f = 0;
 9     while(!isdigit(c)){
10         if(c == '-')
11             f = 1;
12         c = getchar();
13     }
14     while
(isdigit(c)){ 15 a = (a << 3) + (a << 1) + (c ^ '0'); 16 c = getchar(); 17 } 18 return f ? -a : a; 19 } 20 21 const int MAXN = 100010; 22 int dp[16] , dir[16] , C[5]; 23 int N , K , ans , ind1 , ind2; 24 struct ani{ 25 int val[5] , ind; 26 bool operator <(const ani a)const{ 27 return val[K - 1] < a.val[K - 1]; 28 } 29 }now[MAXN]; 30 31 inline int calc(int d , int type){ 32 int sum = 0; 33 for(int i = 0 ; i < K - 1 ; ++i) 34 sum += (type & (1 << i) ? 1 : -1) * now[d].val[i]; 35 return sum; 36 } 37 38 int main(){ 39 #ifndef ONLINE_JUDGE 40 freopen("in" , "r" , stdin); 41 //freopen("out" , "w" , stdout); 42 #endif 43 N = read(); 44 K = read(); 45 for(int i = 0 ; i < K ; ++i) 46 C[i] = read(); 47 for(int i = 1 ; i <= N ; ++i){ 48 for(int j = 0 ; j < K ; ++j) 49 now[i].val[j] = read() * C[j]; 50 now[i].ind = i; 51 } 52 sort(now + 1 , now + N + 1); 53 for(int i = 0 ; i < 1 << (K - 1) ; ++i){ 54 dir[i] = now[1].ind; 55 dp[i] = calc(1 , i) + now[1].val[K - 1]; 56 } 57 for(int i = 2 ; i <= N ; ++i){ 58 for(int j = 0 ; j < 1 << (K - 1) ; ++j){ 59 int t = calc(i , j) , d = (1 << (K - 1)) - 1 - j; 60 if(t + dp[d] - now[i].val[K - 1] > ans){ 61 ans = t + dp[d] - now[i].val[K - 1]; 62 ind1 = now[i].ind; 63 ind2 = dir[d]; 64 } 65 } 66 for(int j = 0 ; j < 1 << (K - 1) ; ++j) 67 if(dp[j] < calc(i , j) + now[i].val[K - 1]){ 68 dp[j] = calc(i , j) + now[i].val[K - 1]; 69 dir[j] = now[i].ind; 70 } 71 } 72 cout << ind1 << ' ' << ind2 << endl << ans; 73 return 0; 74 }