zoukankan      html  css  js  c++  java
  • 【bzoj4004】【JLOI2015】装备购买 (线性基+高斯消元)

    Description

    脸哥最近在玩一款神奇的游戏,这个游戏里有 n 件装备,每件装备有 m 个属性,用向量zi(aj ,.....,am) 表示 (1 <= i <= n; 1 <= j <= m),每个装备需要花费 ci,现在脸哥想买一些装备,但是脸哥很穷,所以总是盘算着怎样才能花尽量少的钱买尽量多的装备。对于脸哥来说,如果一件装备的属性能用购买的其他装备组合出(也就是说脸哥可以利用手上的这些装备组合出这件装备的效果),那么这件装备就没有买的必要了。严格的定义是,如果脸哥买了 zi1,.....zip这 p 件装备,那么对于任意待决定的 zh,不存在 b1,....,bp 使得 b1zi1 + ... + bpzip = zh(b 是实数),那么脸哥就会买 zh,否则 zh 对脸哥就是无用的了,自然不必购买。举个例子,z1 =(1; 2; 3);z2 =(3; 4; 5);zh =(2; 3; 4),b1 =1/2,b2 =1/2,就有 b1z1 + b2z2 = zh,那么如果脸哥买了 z1 和 z2 就不会再买 zh 了。脸哥想要在买下最多数量的装备的情况下花最少的钱,你能帮他算一下吗?

    Input

    第一行两个数 n;m。接下来 n 行,每行 m 个数,其中第 i 行描述装备 i 的各项属性值。接下来一行 n 个数,
    其中 ci 表示购买第 i 件装备的花费。

    Output

    一行两个数,第一个数表示能够购买的最多装备数量,第二个数表示在购买最多数量的装备的情况下的最小花费
     

     题解:

    这乍一看,似乎没有什么规律,但是,仔细一想,这题跟线性基有点像。

    普通的异或线性基是将十进制数转为二进制,将 01 串作为向量,加入线性基,这道题将一个十进制的向量插入线性基。

    我们可以用高斯消元消去最高位替代异或,如下:

    1 bool insert(Vector x){
    2     for(int i=m;i>=1;i--){
    3         if(fabs(x.v[i])<eps)continue;
    4         if(a[i].empty()){a[i]=x;return true;}
    5         double k=x.v[i]/a[i].v[i];
    6         for(int j=1;j<=m;j++)x.v[j]-=a[i].v[j]*k;
    7         if(x.empty())return false;
    8     }
    9 }

    这同样满足线性基的性质,(感性理解)

    COMPLETE  CODE:

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<algorithm>
     4 #include<cmath>
     5 #include<cstring>
     6 using namespace std;
     7 
     8 #define eps 1e-5
     9 int n,m,x,sum,ans;
    10 struct Vector{
    11     double v[505];
    12     int c;
    13     bool operator<(const Vector &b)const{
    14         return c<b.c;
    15     }
    16     bool empty(){
    17         for(int i=1;i<=m;i++)
    18             if(fabs(v[i])>=eps)return false;
    19         return true;
    20     }
    21 }a[505];
    22 struct LB{
    23     Vector a[505];
    24     bool insert(Vector x){
    25         for(int i=m;i>=1;i--){
    26             if(fabs(x.v[i])<eps)continue;
    27             if(a[i].empty()){a[i]=x;return true;}
    28             double k=x.v[i]/a[i].v[i];
    29             for(int j=1;j<=m;j++)x.v[j]-=a[i].v[j]*k;
    30             if(x.empty())return false;
    31         }
    32     }
    33 }lb;
    34 
    35 int main(){
    36     scanf("%d%d",&n,&m);
    37     for(int i=1;i<=n;i++)
    38     for(int j=1;j<=m;j++)scanf("%d",&x),a[i].v[j]=x;
    39     for(int i=1;i<=n;i++)scanf("%d",&a[i].c);
    40     sort(a+1,a+n+1);
    41     for(int i=1;i<=n;i++)
    42         if(lb.insert(a[i]))sum++,ans+=a[i].c;
    43     printf("%d %d",sum,ans);
    44 }

    注意!! 这题卡精度!!

    作者:ezoiLZH
    本文版权归作者和博客园所有,欢迎转载,只要写明原文链接即可(^_^)。
  • 相关阅读:
    HDU4529 郑厂长系列故事——N骑士问题 —— 状压DP
    POJ1185 炮兵阵地 —— 状压DP
    BZOJ1415 聪聪和可可 —— 期望 记忆化搜索
    TopCoder SRM420 Div1 RedIsGood —— 期望
    LightOJ
    LightOJ
    后缀数组小结
    URAL
    POJ3581 Sequence —— 后缀数组
    hdu 5269 ZYB loves Xor I
  • 原文地址:https://www.cnblogs.com/ezoiLZH/p/9383647.html
Copyright © 2011-2022 走看看