• Codeforces Round #162 (Div. 1) C 264C Choosing Balls


    http://codeforces.com/problemset/problem/264/C

    题目意思:

      n个小球排成一列,每个小球有两个属性:颜色ci,权值vi

      然后有q次询问,每次给出两个整数a和b

      求一个权值最大的小球子序列:

        一个序列的权值这样计算:

        当一个小球前面有小球,且颜色相同时,权值为a*vi

        否则为b*vi

        序列的权值为所有小球权值之和。

      长度为0的序列权值视为0,所以本题答案至少为0

    很容易写出状态转移方程dp[i]表示以小球i结束的序列的最大权值

    dp[i] = max( max(dp[j] + (ci == cj?a:b)*vi) (0<=j<i), b*vi )

      1.b*vi 为长度为1的只包含i的序列

      2.max(dp[j] + (ci == cj?a:b)*vi) (0<=j<i) 为当有前缀时的最大值

    当然,同样的,复杂度为n^2,无法承受。

    观察方程,我们可以发现,其实dp[i] = max(颜色与ci不同的j中最大的dp[j]+b*v1, 颜色与ci相同的j中最大的dp[j]+a*v1, b*v1)

    那我们何不直接以颜色为状态呢?dp[i]表示以颜色i结束的序列的最大值。

    状态方程变为

    dp[ci] = max(b*vi, max(dp[j],j!=ci) + b*vi, dp[ci] + a*vi, dp[ci])

    复杂度还是n^2没有优化的地方吗?

    状态转移费用主要耗费在求max(dp[j] | j!=ci)上,我们何不干脆记录当前dp[0..n]的最大值呢?不过万一最大值的i正好与当前的ci相同怎么办?那就是次大的!

    所以记录最大的和次大dp[i]即可完美解决问题!

    当ci与最大的dp[i]颜色相同时,返回次大值,否则返回最大值。同时,每次更新后,更新一下最大值和次大值。

    转移费用马上下降到了1,问题解决!

    注意刚开始把所有dp[i]置为负无穷大,而不是0

    代码如下:

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<iostream>
     4 #include<algorithm>
     5 using namespace std;
     6 typedef long long ll;
     7 const int N=100100;
     8 const ll inf=~0ull>>3;
     9 const ll finf=-inf;
    10 int n,c[N],v[N];
    11 ll a,b,dp[N];
    12 struct poi{
    13     ll mx1,mx2;
    14     int mxc1,mxc2;
    15     void cl(){
    16         mxc1=mxc2=-1;
    17     }
    18     ll getmax(int c){
    19         if(mxc1 == -1) return finf;
    20         else if(c!=mxc1) return mx1;
    21         else if(mxc2 == -1) return finf;
    22         else return mx2;
    23     }
    24     void add(int c,ll mx){
    25         if(mxc1==-1){
    26             mxc1=c;
    27             mx1=mx;
    28         }
    29         else if(c==mxc1){
    30             if(mx>mx1) mx1=mx;
    31         }
    32         else if(mx>mx1){
    33             mxc2=mxc1;
    34             mx2=mx1;
    35             mxc1=c;
    36             mx1=mx;
    37         }
    38         else if(mxc2==-1 || (mx > mx2)){
    39             mxc2=c;
    40             mx2=mx;
    41         }
    42     }
    43 };
    44 void solve(){
    45     for(int i=0;i<n;i++)dp[i]=finf;
    46     dp[c[0]]=b*v[0];
    47     poi pmx;
    48     pmx.cl();
    49     pmx.add(c[0],b*v[0]);
    50     for(int i=1;i<n;i++){
    51         ll tmp=pmx.getmax(c[i]) + b*v[i];
    52         ll tmp2=dp[c[i]] + a*v[i];
    53         tmp=max(tmp,tmp2);
    54         tmp2=b*v[i];
    55         tmp=max(tmp,tmp2);
    56         if(tmp > dp[c[i]]){
    57             dp[c[i]]=tmp;
    58             pmx.add(c[i],tmp);
    59         }
    60     }
    61     ll ans=0;
    62     for(int i=0;i<n;i++)if(dp[i]>ans) ans=dp[i];
    63     printf("%I64d\n",ans);
    64 }
    65 int main()
    66 {
    67     int m;
    68     while (~scanf("%d%d",&n,&m))
    69     {
    70         for(int i=0;i<n;i++)scanf("%d",v+i);
    71         for(int i=0;i<n;i++){
    72             scanf("%d",c+i);
    73             c[i]--;
    74         }
    75         while(m--){
    76             scanf("%I64d%I64d",&a,&b);
    77             solve();
    78         }
    79     }
    80     return 0;
    81 }
  • 相关阅读:
    9月9号作业
    9月9号笔记
    jupyter的补充
    jupyter的使用
    9月6号作业
    编程语言的分类
    计算机组成
    计算机组成的补充
    面向对象基础
    9月2号作业
  • 原文地址:https://www.cnblogs.com/hundundm/p/2870319.html
Copyright © 2020-2023  润新知