HDU5900-QSC and Master-区间DP+区间覆盖DP

地址 http://acm.hdu.edu.cn/showproblem.php?pid=5900

2016ICPC沈阳赛区网络赛

题意:一个队列,每个点有key[i]和value[i],位置相邻且key不互质的两个点可以被取走,取走后,剩下点自动连接起来。

    问取走的value和最大

题解:1.对于所有的区间,用区间DP求出能否 整个 区间取走

      枚举区间长度

      对于[s,e] 的区间,要么由两个比这短的区间拼凑而成,要么s和e可以不互质,且[s+1,e-1]可以取走,特判长度为2的时候。

   2.对于所有能取走的区间,有区间覆盖(覆盖一次)问题

   3.DP解决问题2

      对于所有区间按照终点排序

      对于不是终点的i,dp[i] = dp[i-1]

      对于是终点的i,dp[i] = max( dp[ i - 1 ] , { E.Svalue | E.end == i } )

      坐标轴上的单向最短(长)路问题和这个类似

沈阳站赛前复习,希望自己沈阳加油。

 1 #include <iostream>
 2 #include <cstring>
 3 #include <cstdio>
 4 #include <algorithm>
 5 using namespace std;
 6 long long a[333];
 7 long long b[333];
 8 long long sum[333];
 9 long long dp[333];
10 struct Edge
11 {
12     int s,e;
13     long long val;
14 }E[93333];
15 int ife[333][333];
16 long long gcd(long long aa, long long bb)
17 {
18         return bb == 0 ? aa : gcd(bb,aa % bb);
19 }
20 bool com(Edge A,Edge B)
21 {
22         return A.e < B.e;
23 }
24 void addedge(int s, int e)
25 {
26     ife[s][e] = 1;
27     E[cnt].s = s;
28     E[cnt].e = e;
29     E[cnt].val = sum[e] - sum[s-1];
30     cnt++;
31 }
32 int main()
33 {
34      int T;
35      //freopen("in.txt","r",stdin);
36      cin >> T;
37      while (T--)
38      {
39         memset(E,0,sizeof(E));
40         memset(ife,0,sizeof(ife));
41         memset(dp,0,sizeof(dp));
42         sum[0] = 0;
43         int N;
44         cin >> N;
45         for (int i = 1; i<= N; i++)
46         {
47             scanf("%lld",&a[i]);
48         }
49         for (int i = 1; i<= N; i++)
50         {
51             scanf("%lld",&b[i]);
52             sum[i] = sum[i-1] + b[i];
53         }
54         int cnt = 1;
55         //区间DP建边
56         //如果s,e之间 能通过某种方式全部取出,那么s,e区间建边
57         for (int i = 1; i<=N; i+=2)
58         {
59             for (int s = 1; s+i<=N; s++)
60             {
61                 int e = s+i;
62                 if (ife[s][e] == 1) continue;
63                 if (gcd(a[s],a[e]) != 1LL && (i == 1 || ife[s+1][e-1] == 1))
64                 {
65                     addedge(s,e);
66                     continue;
67                 }
68                 for (int l = s + 1 ;l <= e-2; l += 2 )
69                 {
70                     if (ife[s][l] == 1 && ife[l+1][e] == 1)
71                     {
72                         addedge(s,e);
73                         break;
74                     }
75                 }
76             }
77         }
78         //每个点只能被选一次,转换为区间一次性覆盖,所有的区间都已经经过区间dp求出
79         //区间一次性覆盖 可以用DP求
80         sort(E+1,E+cnt,com);
81         for (int i = 1; i<cnt;)
82         {
83             int te = E[i].e;
84             while (E[i].e == te)
85             {
86                 dp[te] = max(dp[te],dp[E[i].s-1] + E[i].val);
87                 i++;
88             }
89             for (int j = te+1 ; j <= E[i].e ; j++)
90                 dp[j] = dp[j-1];
91         }
92         //此处不要输出dp[N],因为dp的范围就是最后一条边的终点
93         cout << dp[E[cnt-1].e] <<endl;
94      }
95 }
原文地址:https://www.cnblogs.com/HITLJR/p/5974764.html