地址 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 }