大水题

  1 /*
  2   Source   : wannafly21
  3   Problem  :给出一个长度为n的序列,每个位置有一个值和一个权重,可以把两个位置值相同的一段连起来作为一个操作,得分为对应的权重之和,每个位置只能连一次,
  4              求最终最大的和。
  5   Solution :dp[i] = dp[j] + sum(i,j) , a[i]==a[j]
  6              优化: 假设j为i前面一个相同的值,dp[j] 对应的最优位置在x
  7                     那么dp[i]对应对应的最优值的位置在j 或者 x; 位置j是可能的,其余的位置的结果都必然不优于x
  8                     由dp[j]的结果可得,对于任意的一个y a[y]==a[x] 有  dp[x]+sum(x,j) >= dp[y]+sum(y,j)
  9                     相应的就有   dp[x] + sum(x, i) = dp[x] + sum(x, j) + sum(j, i) >= dp[y] + sum(y, j) + sum(j, i) = dp[y] + sum(y, i)
 10   Date     :2018-08-10-11.50
 11 */
 12 
 13 #include <bits/stdc++.h>
 14 using namespace std;
 15 
 16 typedef long long LL;
 17 const int MAXN = 300005;
 18 const LL MOD7 = 1e9+7;
 19 int n;
 20 
 21 LL a[MAXN];
 22 LL g[MAXN];
 23 LL dp[MAXN];
 24 LL sum[MAXN];
 25 int pos[MAXN];
 26 int pre[MAXN];
 27 map<LL, int> mp;
 28 
 29 void work()
 30 {
 31     LL ans=0;
 32     memset(dp,0,sizeof(dp));
 33     memset(pos,0,sizeof(pos));
 34     mp.clear();
 35     memset(pre,0,sizeof(pre));
 36     for (int i=1;i<=n;++i)
 37     {
 38         if (mp.find(a[i])!=mp.end())
 39         {
 40             pre[i]=mp[a[i]];
 41         }
 42         mp[a[i]]=i;
 43         sum[i] = sum[i-1] + g[i];
 44     }
 45     for (int i=1;i<=n;++i)
 46     {
 47         if (pre[i]!=0)
 48         {
 49             dp[i] = dp[pre[i]-1] + sum[i] - sum[pre[i]-1];
 50             pos[i]=pre[i];
 51             if (pre[pre[i]]!=0 && dp[pre[pre[i]]-1] + sum[i]-sum[pre[pre[i]]-1] > dp[i])
 52             {
 53                 dp[i] = dp[pre[pre[i]]-1] + sum[i]-sum[pre[pre[i]]-1];
 54                 pre[i] = pre[pre[i]];
 55             }
 56         }
 57         ans=max(ans, dp[i]);
 58     }
 59     printf("%lld\n",ans);
 60 }
 61 
 62 int main()
 63 {
 64 #ifndef ONLINE_JUDGE
 65     freopen("test.txt","r",stdin);
 66 #endif // ONLINE_JUDGE
 67     int Case;
 68     // scanf("%d",&Case);
 69     while (scanf("%d",&n)!=-1)
 70     {
 71         for (int i=1;i<=n;++i)
 72         {
 73             scanf("%lld",&a[i]);
 74         }
 75         for (int i=1;i<=n;++i)
 76         {
 77             scanf("%lld",&g[i]);
 78         }
 79         work();
 80     }
 81     return 0;
 82 }
 83 
 84 //7
 85 //1 2 1 2 3 2 3
 86 //1 4 3 4 3 4 5
 87 //15
 88 //1 2 1 2 1 2 1 2 1 2 1 2 1 2 1
 89 //5 5 5 5 5 5 5 5 5 5 5 5 5 5 5
 90 //5
 91 //1 2 1 2 1
 92 //5 5 5 5 5
 93 //
 94 //
 95 //
 96 //
 97 //out:
 98 //23
 99 //75
100 //25

猜你喜欢

转载自www.cnblogs.com/LeeSongt/p/9454282.html