洛谷P2672 推销员

沙雕贪心......

我一开始想的是倒着来,每次减去一个。

然后我们就有两个决策:去掉最后一个/去掉前面某一个。

然后第一个决策用并查集维护,第二个决策用线段树即可。仔细想想觉得普及组不会考这种东西,慌得一批。

然后又发现可能有问题:你可能取x个的时候不从x + 1转移过来,而是x + 2

然后就不会了。

然后看提解发现正解是顺着来......什么沙雕。

结论:若取x个的时候最优解是集合S,那么取x+1个时的最优解集合一定包含S。(说明了上面我的做法是对的)

证:

即证对于每一个取x+1的方案p,若不包含S,都可以找到一个包含S的方案比它更优。

设取x个的最优方案为r

考虑最右那一个:

①p的最后那个等于r的最右那一个时,前面我们随便去掉一个不与r配对的位置d,然后p一定还与r不同。

我们把p调整成r,然后加上d,这样就比原来的p更优了。

②p的最后那个小于r的最后那一个时,我们同样去掉一个d,然后调整,最后加上d,就会更优。

③p的最后那个大于r的最后那个时,把p的最后那个去掉,同时p的价值减去(2 * 从r最后到p最后的距离)。

这样就相当于情况①中去掉d之后的p了。

然后调整成r之后把原来p的最后加上,再加上减去的价值,就会比原来的p更优。

 1 #include <cstdio>
 2 #include <algorithm>
 3 #include <queue>
 4 
 5 const int N = 100010;
 6 
 7 int a[N], x[N], g[N];
 8 std::priority_queue<int> Q;
 9 
10 int main() {
11     int n;
12     scanf("%d", &n);
13     for(int i = 1; i <= n; i++) {
14         scanf("%d", &x[i]);
15         x[i] <<= 1;
16     }
17     for(int i = 1; i <= n; i++) {
18         scanf("%d", &a[i]);
19     }
20     
21     for(int i = n; i >= 1; i--) {
22         if(x[i] + a[i] > x[g[i + 1]] + a[g[i + 1]]) {
23             g[i] = i;
24         }
25         else {
26             g[i] = g[i + 1];
27         }
28     }
29     
30     int now = g[1];
31     
32     int ans = a[now] + x[now], pos = 1;
33     printf("%d\n", ans);
34     
35     for(int i = 2; i <= n; i++) {
36         while(pos < now) {
37             Q.push(a[pos]);
38             pos++;
39         }
40         if(pos == now) {
41             pos++;
42         }
43         if(!Q.empty() && Q.top() > a[g[now + 1]] + x[g[now + 1]] - x[now]) {
44             ans += Q.top();
45             Q.pop();
46         }
47         else {
48             ans -= x[now];
49             now = g[now + 1];
50             ans += a[now] + x[now];
51         }
52         printf("%d\n", ans);
53     }
54     
55     return 0;
56 }
AC代码

然后我又打了一开始那个线段树的想法......

  1 #include <cstdio>
  2 #include <algorithm>
  3 #include <queue>
  4 
  5 const int N = 100010, INF = 0x3f3f3f3f;
  6 
  7 int a[N], x[N], ans[N];
  8 int small[N << 2], fa[N]; 
  9 
 10 int find(int x) {
 11     if(fa[x] == x) {
 12         return x;
 13     }
 14     return fa[x] = find(fa[x]);
 15 }
 16 
 17 inline void pushup(int o) {
 18     int ls = o << 1;
 19     int rs = ls | 1;
 20     if(a[small[ls]] <= a[small[rs]]) {
 21         small[o] = small[ls];
 22     }
 23     else {
 24         small[o] = small[rs];
 25     }
 26     return;
 27 }
 28 
 29 void build(int l, int r, int o) {
 30     if(l == r) {
 31         small[o] = r;
 32         return;
 33     }
 34     int mid = (l + r) >> 1;
 35     build(l, mid, o << 1);
 36     build(mid + 1, r, o << 1 | 1);
 37     pushup(o);
 38     return;
 39 }
 40 
 41 int ask(int L, int R, int l, int r, int o) {
 42     if(L <= l && r <= R) {
 43         return small[o];
 44     }
 45     int mid = (l + r) >> 1;
 46     
 47     if(R <= mid) {
 48         return ask(L, R, l, mid, o << 1);
 49     }
 50     if(mid < L) {
 51         return ask(L, R, mid + 1, r, o << 1 | 1);
 52     }
 53     
 54     int as = ask(L, R, l, mid, o << 1);
 55     int t = ask(L, R, mid + 1, r, o << 1 | 1);
 56     if(a[t] < a[as]) {
 57         as = t;
 58     }
 59     return as;
 60 }
 61 
 62 void change(int p, int l, int r, int o) {
 63     if(l == r) {
 64         a[r] = INF;
 65         return;
 66     }
 67     int mid = (l + r) >> 1;
 68     if(p <= mid) {
 69         change(p, l, mid, o << 1);
 70     }
 71     else {
 72         change(p, mid + 1, r, o << 1 | 1);
 73     }
 74     pushup(o);
 75     return;
 76 }
 77 
 78 int main() {
 79     int n, sum = 0;
 80     scanf("%d", &n);
 81     for(int i = 1; i <= n; i++) {
 82         scanf("%d", &x[i]);
 83         x[i] <<= 1;
 84     }
 85     for(int i = 1; i <= n; i++) {
 86         scanf("%d", &a[i]);
 87         fa[i] = i;
 88         sum += a[i];
 89     }
 90     sum += x[n];
 91     ans[n] = sum;
 92     
 93     build(1, n, 1);
 94     
 95     int now = n;
 96     for(int i = n - 1; i >= 1; i--) {
 97         int pos = ask(1, now - 1, 1, n, 1);
 98         if(a[now] + x[now] - x[find(now - 1)] > a[pos]) {
 99             sum -= a[pos];
100             change(pos, 1, n, 1);
101             fa[pos] = find(pos - 1);
102         }
103         else {
104             sum -= (a[now] + x[now] - x[find(now - 1)]);
105             now = find(now - 1);
106         }
107         ans[i] = sum;
108     }
109     
110     for(int i = 1; i <= n; i++) {
111         printf("%d\n", ans[i]);
112     }
113     return 0;
114 }
AC代码

话说这个代码我调都没调,一次就写对了。

 

posted @ 2018-10-19 10:11  huyufeifei  阅读(163)  评论(0编辑  收藏  举报
试着放一个广告栏(虽然没有一分钱广告费)

ReadEra 阅读书籍

『Flyable Heart 応援中!』 HHG 高苗京铃 闪十PSS 双六 電動伝奇堂 章鱼罐头制作组 はきか 祝姬 星降夜