Codeforces Round #260(Div. 1)E

纪念自己过的第一道CF Div.1的E题,不过好多的地方都有点的不太理解,差不多可以说是照着比人的代码打了一遍,以后有空自己再写一遍......

首先,把题目转化为一个贪心问题:对于每个询问(x, y),发现在

  • f(1, j) = a[j], 1 ≤ j ≤ n.
  • f(i, j) = min(f(i - 1, j), f(i - 1, j - 1)) + a[j], 2 ≤ i ≤ ni ≤ j ≤ n.

这两个条件中,可以想象一下,从y, y走到1, l的某个位置,而且路径上y坐标不会增加,而且l是[l,y]中最小的那个数,代价就为sum[y] - sum[l] + a[l]·(x - y + l)

最小的那个点肯定要尽可能多用

于是一顿乱推得到一个 sum[y] + a[l]·(x - y) + a[l]·l - sum[l], 令k = a[l], X = x - y, b = a[l] * l - sum[l],发现和y = k * x + b很像,于是就可以依靠这个来解决问题了

期中sum[y]在那个式子里面可有可无,所以可以单独提出来

然后就是靠线段树来维护一个凸包,为什么要用凸包呢?为什么要会线段树呢?

如果你求出了一个下凸包(其实感觉有点像半平面交),对于一个点x,凸包上的直线满足一个很好的性质,就是这些线是按k排序的,于是就可以二分

怎么维护呢?类似于归并排序的方法,不过为了方便询问就利用了线段树

代码

  1 #include <set>
  2 #include <map>
  3 #include <queue>
  4 #include <deque>
  5 #include <cmath>
  6 #include <vector>
  7 #include <string>
  8 #include <cstdio>
  9 #include <cstdlib>
 10 #include <cstring>
 11 #include <cassert>
 12 #include <iostream>
 13 #include <algorithm>
 14
 15 using namespace std;
 16
 17 typedef long long LL;
 18 typedef pair <int, int> PII;
 19
 20 const int N = 1e5 + 7;
 21 const int INF = 0x3f3f3f3f;
 22 const int MOD = 1e9 + 7;
 23 const double EPS = 1e-6;
 24 const double PI = acos(-1.0);
 25
 26 int data[N], sum[N];
 27
 28 struct ConvexHull{
 29     vector <int> k, b;
 30     void clear(){
 31         k.clear();
 32         b.clear();
 33     }
 34     double Intersect(int k1, int b1, int k2, int b2){
 35         return (double)(b2 - b1) / (k1 - k2);
 36     }
 37     void push(int kk, int bb){
 38         int n = k.size();
 39         while (n > 1 && ((k.back() == kk && b.back() > bb) || (k.back() != kk &&
 40                 Intersect(k[n - 1], b[n - 1], k[n - 2], b[n - 2]) > Intersect(k[n - 1], b[n - 1], kk, bb)))){
 41             --n;
 42             k.pop_back();
 43             b.pop_back();
 44         }
 45         while (n && k.back() == kk && b.back() > bb){
 46             --n;
 47             k.pop_back();
 48             b.pop_back();
 49         }
 50         if (n && k.back() == kk && b.back() <= bb){
 51             return;
 52         }
 53         k.push_back(kk);
 54         b.push_back(bb);
 55     }
 56     int get(int x){
 57 //        printf("Calc %d\n", x);
 58 //        int res = INF;
 59 //        for (int i = 0; i < k.size(); ++i){
 60 //            res = min();
 61 //        }
 62         int l = 0, r = k.size() - 1, mid;
 63         while (l < r){
 64             mid = (l + r) >> 1;
 65             if (k[mid] * x + b[mid] < k[mid + 1] * x + b[mid + 1])
 66                 r = mid;
 67             else
 68                 l = mid + 1;
 69         }
 70         return k[l] * x + b[l];
 71     }
 72     void debug(){
 73         for (int i = 0; i < k.size(); ++i)
 74             printf("%d %d\n", k[i], b[i]);
 75     }
 76 };
 77
 78 struct Node{
 79     int a, b;
 80     ConvexHull g;
 81     Node *l, *r;
 82 };
 83
 84 struct SegmentTree{
 85     Node tree[N << 1], *root;
 86     int pos;
 87
 88     void merge(ConvexHull &res, const ConvexHull &a, const ConvexHull & b){
 89         res.clear();
 90         int p1 = 0, p2 = 0;
 91         while (p1 < a.k.size() && p2 < b.k.size()){
 92             if (a.k[p1] > b.k[p2]){
 93                 res.push(a.k[p1], a.b[p1]);
 94                 ++p1;
 95             } else {
 96                 res.push(b.k[p2], b.b[p2]);
 97                 ++p2;
 98             }
 99         }
100         while (p1 < a.k.size()){
101             res.push(a.k[p1], a.b[p1]);
102             ++p1;
103         }
104         while (p2 < b.k.size()){
105             res.push(b.k[p2], b.b[p2]);
106             ++p2;
107         }
108     }
109
110     Node *build(int a, int b){
111         Node *root = &tree[++pos];
112         root->a = a;
113         root->b = b;
114         if (a == b){
115             root->g.clear();
116             root->g.push(data[a], data[a] * a - sum[a]);
117             return root;
118         }
119         int mid = (a + b) >> 1;
120         root->l = build(a, mid);
121         root->r = build(mid + 1, b);
122 //        printf("Merge : [%d - %d]\n", a, b);
123 //        printf("A : \n");
124 //        root->l->g.debug();
125 //        printf("B : \n");
126 //        root->r->g.debug();
127         merge(root->g, root->l->g, root->r->g);
128 //        printf("Res : \n");
129 //        root->g.debug();
130         return root;
131     }
132
133     void init(int n){
134         pos = 0;
135         root = build(1, n);
136     }
137
138     int find(Node *root, int a, int b, int x){
139         if (a <= root->a && root->b <= b){
140             return root->g.get(x);
141         }
142         int mid = (root->a + root->b) >> 1, res = 0;
143         if (a <= mid)
144             res = min(res, find(root->l, a, b, x));
145         if (b > mid)
146             res = min(res, find(root->r, a, b, x));
147         return res;
148     }
149
150     int query(int x, int y){
151         return find(root, y - x + 1, y, x - y);
152     }
153 }tree;
154
155 int main(void){
156     freopen("a.in", "r", stdin)
157     freopen("a.out", "w", stdout);
158     int n;
159     scanf("%d", &n);
160     for (int i = 1; i <= n; ++i){
161         scanf("%d", &data[i]);
162         sum[i] = sum[i - 1] + data[i];
163     }
164     tree.init(n);
165     int Q, x, y;
166     scanf("%d", &Q);
167     while (Q--){
168         scanf("%d%d", &x, &y);
169         printf("%d\n", sum[y] + tree.query(x, y));
170     }
171     return 0;
172 }
时间: 2024-08-17 22:04:15

Codeforces Round #260(Div. 1)E的相关文章

Codeforces Round #260 (Div. 2)

A. Laptops 题目意思: 给定n台电脑,第i台电脑的价格是ai ,质量是bi ,问是否存在一台电脑价格比某台电脑价格底,但质量确比某台电脑的质量高,即是否存在ai < aj 且 bi > bj ? 解题思路: 这题一定要看题目,a都是1~n的不同数,b也是1~n的不同数,此题只需要判断ai 是否等于bi ,如果ai != bi 的话,则输出“Happy Alex”,如果所有的ai  == bi 则输出“Poor Alex” 证明:先将a按照从小到大排序,当i<j时ai <

Codeforces Round #260 (Div. 1) A. Boredom (DP)

题目链接:http://codeforces.com/problemset/problem/455/A A. Boredom time limit per test 1 second memory limit per test 256 megabytes input standard input output standard output Alex doesn't like boredom. That's why whenever he gets bored, he comes up with

dp解Codeforces Round #260 (Div. 2)C. Boredom

#include<iostream> #include<map> #include<string> #include<cstring> #include<cstdio> #include<cstdlib> #include<cmath> #include<queue> #include<vector> #include<algorithm> using namespace std; lo

递推DP Codeforces Round #260 (Div. 1) A. Boredom

题目传送门 1 /* 2 DP:从1到最大值,dp[i][1/0] 选或不选,递推更新最大值 3 */ 4 #include <cstdio> 5 #include <algorithm> 6 #include <cmath> 7 #include <cstring> 8 using namespace std; 9 10 typedef long long ll; 11 const int MAXN = 1e5 + 10; 12 const int INF

Codeforces Round #260 (Div. 2) A. Laptops(简单题)

题目链接:http://codeforces.com/problemset/problem/456/A A. Laptops time limit per test 1 second memory limit per test 256 megabytes input standard input output standard output One day Dima and Alex had an argument about the price and quality of laptops.

Codeforces Round #260 (Div. 2) B. Fedya and Maths(循环节)

题目链接:http://codeforces.com/problemset/problem/456/B B. Fedya and Maths time limit per test 1 second memory limit per test 256 megabytes input standard input output standard output Fedya studies in a gymnasium. Fedya's maths hometask is to calculate t

DP Codeforces Round #260 (Div. 1) A. Boredom

题目传送门 1 /* 2 题意:选择a[k]然后a[k]-1和a[k]+1的全部删除,得到点数a[k],问最大点数 3 DP:状态转移方程:dp[i] = max (dp[i-1], dp[i-2] + (ll) i * cnt[i]); 4 只和x-1,x-2有关,和顺序无关,x-1不取,x-2取那么累加相同的值,ans = dp[mx] 5 */ 6 #include <cstdio> 7 #include <algorithm> 8 #include <cstring&

Codeforces Round #260 (Div. 2) ABCDE

A题逗比了,没有看到All ai are distinct. All bi are distinct. 其实很水的.. 1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 using namespace std; 6 7 #define mnx 100002 8 9 10 struct latop{ 11 int p, q; 12 bo

Codeforces Round #260 (Div. 1)——Civilization

题目链接 题意: n个点,m条边的森林,q次操作.每次操作:1.询问x所在树的直径 2.合并x和y所在的树,使得合并后的直径最小 (1?≤?n?≤?3·105; 0?≤?m?<?n; 1?≤?q?≤?3·105) 分析: 没有读到图是森林...做的好纠结 最开始将每个树都求一下直径,之后使用并查集处理,每次合并直径:至少是两个树的直径,或者将两个直径的最中间的部分连接求直径 const int MAXN = 310000; int rt[MAXN], ans[MAXN]; VI G[MAXN];

Codeforces Round #260 (Div. 1)

大三目标把codeforces打成黄色以上! 从div1下手,每次做前三道题. A 一道简单的DP. #include<iostream> #include<algorithm> #include<cstring> #include<cstdio> #include<cstdlib> #include<string> #include<cmath> #include<vector> #define LL lon