混沌DM

DM Hunter

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

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 }

 

 

 

posted on 2013-01-21 20:07  混沌DM  阅读(473)  评论(0编辑  收藏  举报