关于TJOI2014的一道题——Alice and Bob

Posted on 2014-05-16 10:54  SymenYang  阅读(801)  评论(0编辑  收藏  举报

B Alice and Bob

输入输出文件: alice.in/alice.out

•源文件名: alice.cpp/alice.c/alice.pas

• 时间限制: 1s 内存限制: 128M

题目描述

Alice 和 Bob 发明了一个新的游戏。给定一个序列{x0,x1,··· ,xn−1}。Alice得 到一个序列 {a0,a1,··· ,an−1},其中 ai 表示以 xi 结尾的最长上升子序列的长 度;Bob 得到一个序列 {b0,b1,··· ,bn−1},其中 bi 表示以 xi 开头的最长下降 子序列的长度。Alice的得分是序列 {a0,a1,··· ,an−1} 的和,Bob的得分是 {b0,b1,··· ,bn−1}的和。 输输输入入入 输入的第一行是 n,第二行是序列{a0,a1,··· ,an−1}。数据保证序列 a 可以由 至少一个 1 到 n 的排列得到。

输出
输出包含一行,表示 Bob 能得到的最高分数。
样例输入1
4 1 2 2 3
样例输出1
5
样例输入2
4 1 1 2 3
样例输出2
5
数据范围 对于 30%

的数据,N ≤ 1000

对于 100% 的数据,N ≤ 10^5

这道题一看到的时候觉得可做,马上写出了一个转移方程 f[i]表示从后往前值为 i 时最长的答案,觉得似乎只能从后面 的 a值小于i的地方转移过来,然后就比SCOIDay1T1简单,用同样的思路加树状数组就出来了。但是后来再检查的时候仔细推了一下,发现有些不对。

对于两个位置p,q(p<q) 如果a[p]>=a[q] 那么x[p]>x[q] ,这一点很显而易见,但是如果a[p]<a[q]并不能推出x[p]<x[q]比如x为1 6 2 5 3 4时a值为1 2 2 3 3 4 a[2]<a[6]但是x[2]>x[6],所以说有一定问题。我们发现,如果满足a[p]<a[q]&&x[p]>x[q]则一定存在另一个序列从p后面等于a[p]这个值开始,不断累加可以得到,比如a[2]后面a[3]==a[2] ,a[4]==a[3]+1,a[6]==a[4]+1,所以第6个位置可能比第二个位置小

然后就得到了一个暴力的方法,小于的像原来那样弄,大于的N^2来搞,这样子可以得30分

然后想优化,思想上比较麻烦,写起来很简单,直接看代码吧:

  1 #include <cstdio>
  2 #include <cstdlib>
  3 #include <algorithm>
  4 #include <iostream>
  5 using namespace std;
  6 int lowbit(int x) {return x&-x;}
  7 
  8 int num[100010];
  9 int n;
 10 void change(int data,int pos)
 11 {
 12     while (pos<=n)
 13     {
 14         num[pos]=max(num[pos],data);
 15         pos+=lowbit(pos);
 16     }
 17 }
 18 
 19 int getans(int pos)
 20 {
 21     int ret=0;
 22     while (pos>0)
 23     {
 24         ret=max(ret,num[pos]);
 25         pos-=lowbit(pos);
 26     }
 27     return ret;
 28 }
 29 
 30 int a[100010];
 31 int f[100010];
 32 int fself[100010];
 33 int nextc[100010];
 34 int nextb[100010];
 35 int last[100010];
 36 int maxd[100010];
 37 void pre()
 38 {
 39     for (int i=n;i>=1;--i)
 40     {
 41         nextc[i]=last[a[i]];
 42         last[a[i]]=i;
 43         nextb[i]=last[a[i]+1];
 44     }
 45 }
 46 
 47 void trans(int k)
 48 {
 49     fself[k]=fself[nextb[k]];
 50     fself[k]=max(fself[k],maxd[a[k]]);
 51 }
 52 
 53 int getbigans(int k)
 54 {
 55     return fself[nextc[k]]+1;
 56 }
 57 
 58 int viodp()
 59 {
 60     int ret=0;
 61     for (int i=n;i>=1;--i)
 62     {
 63         f[i]=1;
 64         for (int j=i+1;j<=n;++j)
 65         {
 66             if (a[j]<=a[i])
 67                 f[i]=max(f[i],f[j]+1);
 68         }
 69         int now=a[i];
 70         for (int j=i+1;j<=n;++j)
 71         {
 72             if (a[j]<=now&&a[j]>a[i])
 73                 f[i]=max(f[i],f[j]+1);
 74             if (a[j]==now)
 75             {
 76                 now=now+1;
 77             }
 78         }    
 79         ret+=f[i];
 80     }
 81 //    cout<<endl;
 82     return ret;
 83 }
 84 
 85 long long dp()
 86 {
 87     long long ret=0;
 88     for (int i=n;i>=1;--i)
 89     {
 90         int f=getans(a[i])+1;
 91         f=max(f,getbigans(i));
 92         maxd[a[i]]=max(maxd[a[i]],f);
 93         trans(i);
 94         change(f,a[i]);
 95         ret+=f;
 96     }
 97     return ret;
 98 }
 99 
100 int main()
101 {
102     freopen ("alice.in","r",stdin);
103     freopen ("alice.out","w",stdout);
104     scanf("%d",&n);
105     for (int i=1;i<=n;++i)
106     {
107         scanf("%d",&a[i]);
108     }
109     if (n<=1000)
110     {
111         cout<<viodp()<<endl;
112         return 0;
113     }
114     pre();
115     cout<<dp()<<endl;
116     return 0;
117 }
View Code

Viodp就是暴力的DP

自己看着理解理解吧。。。其实我觉得这道DP不错,有些意思。似乎其他人写了什么拓扑排序只有50分。