bzoj 1150
思路:写的时候感觉是贪心但是没有什么思路... 看了题解,原来有一个选了能反悔的贪心思路, 如果最优那么每个城市只能和旁边的相邻
城市连边,所以问题变成了由n个数,不能取相邻的两个数,取k个最小是多少。 我们将这n个数放进优先队列里边贪心地取小的,取完最小
的之后,把当前这个now和当前这个的左边l[now]和右边r[now]的删掉,再加入一个 a[l[now]] + a[r[now]] - a[now], 下次选到这个就表明反悔啦
即选了两边那个,中间那个不选, 需要注意的是拿掉的是最左或者最右是不用插入新的值的, l, r需要用链表维护一下。
以后贪心题要考虑能不能设计出一种能让它反悔的方式。
1 #include<bits/stdc++.h> 2 #define LL long long 3 #define fi first 4 #define se second 5 #define mk make_pair 6 #define pii pair<int,int> 7 #define piii pair<int, pair<int,int>> 8 9 10 using namespace std; 11 12 const int N=2e5+7; 13 const int M=1e4+7; 14 const int inf=0x3f3f3f3f; 15 const LL INF=0x3f3f3f3f3f3f3f3f; 16 const int mod=1e9 + 7; 17 18 int n, k, tot, b[N], a[N * 4], l[N], r[N]; 19 bool in[N]; 20 int main() { 21 scanf("%d%d", &n, &k); 22 for(int i = 1; i <= n; i++) 23 scanf("%d", &b[i]); 24 for(int i = 2; i <= n; i++) 25 a[++tot] = b[i] - b[i - 1]; 26 27 for(int i = 1; i <= tot; i++) { 28 l[i] = i - 1; 29 if(i != tot) r[i] = i + 1; 30 else r[i] = 0; 31 } 32 LL ans = 0; 33 priority_queue<pii, vector<pii>, greater<pii> > que; 34 for(int i = 1; i <= tot; i++) { 35 que.push(mk(a[i], i)); 36 } 37 while(k) { 38 pii now = que.top(); 39 que.pop(); 40 if(in[now.se] == true) continue; 41 k--; 42 ans += now.fi; 43 pii u; 44 if(l[now.se] != 0 && r[now.se] != 0) 45 u = mk(0, ++tot); 46 else u = mk(0, 0); 47 u.fi = a[l[now.se]] + a[r[now.se]] - now.fi; 48 a[u.se] = u.fi; 49 in[now.se] = true; 50 in[l[now.se]] = true; 51 in[r[now.se]] = true; 52 in[u.se] = true; 53 int ll = l[l[now.se]], rr = r[r[now.se]]; 54 l[u.se] = ll; 55 r[u.se] = rr; 56 if(ll) r[ll] = u.se; 57 if(rr) l[rr] = u.se; 58 if(l[now.se] !=0 && r[now.se] != 0) que.push(u), in[u.se] = false; 59 } 60 printf("%lld\n", ans); 61 return 0; 62 } 63 /*64 */