luogu4131 [WC2005]友好的生物

题目

分析

part 1

思维难度挺大的一道题,建议先看看这篇blog及2005国家集训队ysy的解题报告(解题报告的链接在这篇blog里):

[WC2005]友好的生物

还有2006陈启峰的论文:一张一弛,解题之道

part 2

先由简,不考虑a[k],那么这样直接求怎么求呢?

直接枚举O(n2k)当然可以,只不过会超时;

有没有一种方法可以避免一些不必要的枚举呢?

这道题最大的阻碍就是这个绝对值问题了,因为它只跟两个生物的具体属性的相对大小有关,所以难以确定,必须枚举。

如果有办法把他给确定了,问题就好解决了。

part 3

看看 k 的数据范围,很容易想到可以从k下手;

抓住绝对值中的‘-’是不变的,也就是说,同一属性两种生物的符号是相反的

有什么用?(用处可大了)

说明对被减数取个负,他们的同一属性的符号就一样了呀。

这样的话,对于每个符号方案,求出每个生物的属性和,再相减不就可以了?

这个符号下放到每个属性,一共就有2k-1种符号方案(先不考虑第k种)

你可能会说,这不一定是绝对值

但是这里面一定包含绝对值,不是绝对值的答案一定会比正确答案小(废话因为是负数)

part 4

枚举每一种符号方案(可以用状压01串表示+-),求出里面的最大差就好,这个可以在O(n)的复杂度里求出来;

边枚举边维护一个min值,用当前值与min值得差更新答案,用当前值更新min值,这样这道题的大致框架就出来了

part 5

考虑a[k],它取的是绝对值的相反数,怎么考虑它呢?

如果它的符号也随机,按照枚举来,这样不能保证a[k]的贡献为负贡献,也不能保证最大差就是正确答案

那多出来的错误答案便是把a[k]弄成了正贡献;

要避免这类情况。

他的特征是小数减大数,我们需要一种方法,既满足最大差就是正确答案,又满足a[k]的性质;

不考虑a[k]的方法与生物的顺序无关,与某一种属性的大小也无关,但是a[k]就明显与大小有关了

a[k]必须保证是小数减大数,而其他的属性随意,这样就可以保证最大差就是正确答案;

既然a[k]与大小有关,不如就按照a[k]的大小确定加减,a[k]小的为被减数,而a[k]的符号确定为+。

这样做能否保证上述方法的正确性呢?

这样做,保证了第k种属性对答案的贡献为负,前面的符号仍然是枚举符号,而a[k]的符号确定,这样再求最大差,仍然是满足正确性

不如就按照a[k]的大小排序,保证a[k]大的在前面,只考虑减去比a[k]它大的生物,这样就可以按照part 4的方法在O(n)的时间中求出最大差

题解:

 

代码

  1 /***************************
  2 User:Mandy.H.Y
  3 Language:c++
  4 Problem:species
  5 Algorithm:
  6 Score:
  7 ***************************/
  8 #include<bits/stdc++.h>
  9 
 10 using namespace std;
 11 
 12 const int maxn = 1e5 + 5;
 13 const int maxk = 6;
 14 
 15 int n,k,cur,ans,ans1,ans2,curid;
 16 int c[maxk];
 17 
 18 struct Node{
 19     int a[10],id;
 20     bool operator <(const Node &b)const {
 21         return a[k] > b.a[k];
 22     }
 23 }p[maxn]; 
 24 
 25 template<class T>inline void read(T &x){
 26     x = 0;bool flag = 0;char ch = getchar();
 27     while(!isdigit(ch)) flag |= ch == '-',ch = getchar();
 28     while(isdigit(ch)) x = (x << 1) + (x << 3) + (ch ^ 48),ch = getchar();
 29     if(flag) x = -x;
 30 }
 31 
 32 template<class T>void putch(const T x){
 33     if(x > 9) putch(x / 10);
 34     putchar(x % 10 | 48);
 35 }
 36 
 37 template<class T>void put(const T x){
 38     if(x < 0) putchar('-'),putch(-x);
 39     else putch(x);
 40 }
 41 
 42 void file(){
 43     freopen("species.in","r",stdin);
 44     freopen("species.out","w",stdout);
 45 }
 46 
 47 void readdata(){
 48     read(n);read(k);
 49     for(int i = 1;i <= k; ++ i) read(c[i]);
 50     
 51     for(int i = 1;i <= n; ++ i){
 52         p[i].id = i;
 53         for(int j = 1;j <= k; ++ j){
 54             read(p[i].a[j]);
 55             p[i].a[j] *= c[j];                    
 56         }
 57     }
 58 } 
 59 
 60 void work(){
 61     sort(p + 1,p + n + 1);
 62     ans = -2e9;
 63     for(int i = 0;i < (1 << (k - 1)); ++ i){
 64         
 65         cur = p[1].a[k];curid = p[1].id;
 66         for(int l = 1;l <= k - 1 ; ++ l){
 67             if(i & (1 << (l - 1))) cur += p[1].a[l];
 68             else cur -= p[1].a[l];
 69         }
 70         
 71         for(int j = 2;j <= n; ++ j){
 72             int now = p[j].a[k];
 73             for(int l = 1;l <= k - 1 ; ++ l){
 74                 if(i & (1 << (l - 1))) now += p[j].a[l];
 75                 else now -= p[j].a[l];
 76             } 
 77             if(now - cur > ans){
 78                 ans = now - cur;
 79                 ans1 = curid;
 80                 ans2 = p[j].id;
 81             }
 82             
 83             if(now < cur){
 84                 cur = now;
 85                 curid = p[j].id;
 86             }
 87         }
 88     }
 89     put(ans1);putchar(' ');put(ans2);putchar('
');
 90     put(ans);
 91  
 92 }
 93 
 94 
 95 int main(){
 96 //    file();
 97     readdata();
 98     work(); 
 99     return 0;
100 }
View Code
非做顽石不可,哪管他敬仰暗唾
原文地址:https://www.cnblogs.com/Mandy-H-Y/p/11410284.html