区间的价值
从1到n分别假设每个数字为区间中的最小值。当假设a[i]为区间最小值时,区间最大值可能在左侧也可能在右侧,两种情况下处理的方式类似,这里只描述一下在左边时的情形。首先从a[i-1]开始向左边找到一个当a[i]为区间最小值时可以作为区间最大值的a[j],则应满足的条件为a[j]>a[i]且当j<k<i时,a[j]>=a[k]>=a[i]。然后从a[j-1]继续向左找到最小的下标l使得当l<=k<j时,a[j]>=a[k]>=a[i]。从a[i+1]向右找到最大的下标r使得当i<k<=r时,a[j]>=a[k]>=a[i]。区间左端点在[l,j],右端点在[i,r]的区间最大值和最小值均分别为a[j]和a[i],其长度最短为i-j+1,最长为r-l+1,以a[i]*a[j]的值更新相应的ans。重复此过程,直到找不到满足条件的j。
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
#include <stdio.h> #include <string.h> long long a[100005], ans[100005]; int main() { int n, l, r, j; long long max; while (scanf("%d", &n) != EOF) { for (int i = 1; i <= n; i++) { scanf("%lld", &a[i]); } memset(ans, 0, sizeof(ans)); for (int i = 1; i <= n; i++) { j = r = i; max = a[i]; while (j >= 1) { if (a[j] < max) { break; } l = j; while (r + 1 <= n && a[i] <= a[r + 1] && a[r + 1] <= a[j]) { r++; } while (l - 1 >= 1 && a[i] <= a[l - 1] && a[l - 1] <= a[j]) { l--; } long long tmp = a[i] * a[j]; for (int k = (i - j + 1); k <= (r - l + 1); k++) { if (tmp > ans[k]) { ans[k] = tmp; } } max = a[j]; j = l - 1; } j = l = i; max = a[i]; while (j <= n) { if (a[j] < max) { break; } r = j; while (l - 1 >= 1 && a[i] <= a[l - 1] && a[l - 1] <= a[j]) { l--; } while (r + 1 <= n && a[i] <= a[r + 1] && a[r + 1] <= a[j]) { r++; } long long tmp = a[i] * a[j]; for (int k = (j - i + 1); k <= (r - l + 1); k++) { if (tmp > ans[k]) { ans[k] = tmp; } } max = a[j]; j = r + 1; } } for (int i = 1; i <= n; i++) { printf("%lld\n", ans[i]); } } return 0; }
刷题计划
对于每一种可能的选择策略,设其第一种代价之和为x,第二种代价之和为y,得到有序数对(x,y)可以作为平面上的一个点来看。所有的策略构成了一大堆点,要找其中xy乘积最小的点可以看成是找一条最接近坐标轴且通过其中一个点的双曲线,显然此双曲线xy=c的c即为xy最小的乘积。首先先分别只考虑两种代价中的一种通过dp来得出最小的代价,设点A(x1,y1)为第一种代价之和最小的点,点B(x2,y2)为第二种代价之和最小的点,则所求的点C一定在AB的左下方。我们寻找离AB最远的点C,然后在AC和CB的左下方递归寻找最远的点,直到不存在更左下的点位置。
一般地,当寻找点A(x1,y1)和点B(x2,y2)左下方最远的点C时,可以转化为寻找使三角形ABC面积最大的点,如图所示:
用方块圈起来的部分可以看做常量,因此,要使ABC面积最大,只需使[(y1-y2)x+(x2-x1)y]最小即可。此时x和y为相加的关系,因此可以把两种代价合成为一种代价,然后根据这个代价进行dp,找到价值大于等于m中xy乘积最小的点C。
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
#include<map> #include<set> #include<queue> #include<stack> #include<cmath> #include<cstdio> #include<bitset> #include<string> #include<vector> #include<cstring> #include<iostream> #include<algorithm> #include<functional> using namespace std; typedef __int64 LL; const int low(int x) { return x & -x; } const int INF = 0x7FFFFFFF; const int mod = 1e9 + 7; const int maxn = 8e2 + 10; LL ans, dp[maxn]; int x[maxn], y[maxn], z[maxn]; int n, m, s; struct pii { int x, y; pii(int x = 0, int y = 0) : x(x), y(y) {} void read() { scanf("%d%d", &x, &y); } } f[maxn]; pii operator +(pii a, pii b) { return pii(a.x + b.x, a.y + b.y); } pii get(int X, int Y) { dp[0] = 0; f[0] = pii(0, 0); for (int i = 1; i <= s; i++) { dp[i] = 1LL << 62; } for (int i = 1; i <= n; i++) { LL v = (LL)y[i] * X + (LL)z[i] * Y; for (int j = s; j >= x[i]; j--) { if (dp[j] <= dp[j - x[i]] + v) { continue; } dp[j] = dp[j - x[i]] + v; f[j] = f[j - x[i]] + pii(y[i], z[i]); } } int k = m; for (int i = m; i <= s; i++) if (dp[i] < dp[k]) { k = i; } ans = min(ans, (LL)f[k].x * f[k].y); return f[k]; } void solve(pii x, pii y) { pii t = get(x.y - y.y, y.x - x.x); if (1LL * (x.x - y.x) * (t.y - y.y) <= 1LL * (x.y - y.y) * (t.x - y.x)) { return; } solve(x, t), solve(t, y); } int main() { while (scanf("%d%d", &n, &m) != EOF) { ans = 1LL << 62; s = 0; for (int i = 1; i <= n; i++) { scanf("%d%d%d", &x[i], &y[i], &z[i]); s += x[i]; } solve(get(1, 0), get(0, 1)); printf("%I64d\n", ans); } return 0; }
瞬间移动
C(n + m - 4, m - 2)
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
#include <stdio.h> #include <string.h> template <class T, int size> class NoCombination { public: T fac[size], inv[size], f[size]; T mod; void init(T m) { mod = m; fac[0] = fac[1] = inv[0] = inv[1] = f[0] = f[1] = 1; for (int i = 2; i < size; i++) { fac[i] = fac[i - 1] * i % mod; f[i] = (mod - mod / i) * f[mod % i] % mod; inv[i] = inv[i - 1] * f[i] % mod; } } int C(int a, int b) { return fac[a] * inv[b] % mod * inv[a - b] % mod; } }; NoCombination<long long, 200005> c; int main() { int n, m; c.init(1000000007); while (scanf("%d%d", &n, &m) != EOF) { printf("%d\n", c.C(n + m - 4, m - 2)); } return 0; }
货物运输
二分答案,判断时间要求为mid是否可行的方式为。草,不写了,表达能力太差,这都说不清楚,我就是个智障。
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
#include <stdio.h> #include <string.h> #include <algorithm> using namespace std; inline int scan() { int res = 0, ch, flag = 0; if ((ch = getchar()) == '-') { flag = 1; } else if (ch >= '0' && ch <= '9') { res = ch - '0'; } while ((ch = getchar()) >= '0' && ch <= '9') { res = res * 10 + ch - '0'; } return flag ? -res : res; } int bp[1000005], bn[1000005], n, m; bool check(int mid) { //b = r - l int bpmax = -1, bpmin = (n << 1), bnmax = -1, bnmin = (n << 1); for (int i = 0; i < m; i++) { if (bp[i] <= mid) { continue; } bpmax = max(bpmax, bp[i]); bpmin = min(bpmin, bp[i]); bnmax = max(bnmax, bn[i]); bnmin = min(bnmin, bn[i]); } if ((bpmax - bpmin) == ((n << 1) + 1) && (bnmax - bnmin) == ((n << 1) + 1)) { return true; } if (bpmax - bpmin > (mid << 1)) { return false; } if (bnmax - bnmin > (mid << 1)) { return false; } return true; } int main() { #ifndef ONLINE_JUDGE freopen("input.txt", "r", stdin); #endif int l, r; while (scanf("%d%d", &n, &m) != EOF) { for (int i = 0; i < m; i++) { scanf("%d%d", &l, &r); bp[i] = r > l ? r - l : l - r; bn[i] = r + l; } l = 0, r = n; while (l + 1 < r) { int mid = (l + r) >> 1; if (check(mid)) { r = mid; } else { l = mid; } } printf("%d\n", r); } return 0; }
区间交
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
#include<stdio.h> #include<algorithm> #include<string.h> #include<math.h> #include<string> #include<iostream> #include<queue> #include<stack> #include<map> #include<vector> #include<set> using namespace std; typedef long long LL; #define mid (L+R)/2 #define lson rt*2,L,mid #define rson rt*2+1,mid+1,R #pragma comment(linker, "/STACK:102400000,102400000") const int maxn = 1e5+300; const int INF = 0x3f3f3f3f; typedef long long LL; typedef unsigned long long ULL; LL presum[maxn]; struct Interval{ int l, r; }intervals[maxn]; struct Seg{ int cover; }segs[maxn*4]; bool cmp(Interval a, Interval b){ return a.r < b.r; // } void PushUp(int rt){ segs[rt].cover = segs[rt*2].cover + segs[rt*2+1].cover; } void buildtree(int rt,int L,int R){ if(L == R){ segs[rt].cover = 0; return; } buildtree(lson); buildtree(rson); PushUp(rt); } void Update(int rt,int L,int R,int id){ if(L == R){ segs[rt].cover++; return ; } if(id <= mid){ Update(lson,id); }else{ Update(rson,id); } PushUp(rt); } int query(int rt,int L, int R,int k){ if(L == R){ return L; } if(k <= segs[rt*2].cover){ return query(lson,k); }else{ return query(rson,k-segs[rt*2].cover); } } int main(){ int n, k, m; while(scanf("%d%d%d",&n,&k,&m)!=EOF){ buildtree(1,1,n); LL a; for(int i = 1; i <= n; i++){ scanf("%lld",&a); presum[i] = presum[i-1] + a; } int l, r; for(int i = 1; i <= m; i++){ scanf("%d%d",&l,&r); intervals[i].l = l; intervals[i].r = r; } sort(intervals+1,intervals+1+m,cmp); for(int i = m-k+1; i <= m; i++){ Update(1,1,n,intervals[i].l); } LL ans = 0; for(int i = m-k+1; i >= 1; i--){ int l = query(1,1,n,k); if(l <= intervals[i].r){ ans = max(ans, presum[intervals[i].r] - presum[l-1]); } Update(1,1,n,intervals[i-1].l); } printf("%lld\n",ans); } return 0; }
中位数计数
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
#include <stdio.h> #include <string.h> int a[8005]; int l[16005]; int main() { #ifndef ONLINE_JUDGE freopen("input.txt", "r", stdin); #endif int n, ans; while (scanf("%d", &n) != EOF) { for (int i = 1; i <= n; i++) { scanf("%d", &a[i]); } for (int i = 1; i <= n; i++) { int tmp = 0; memset(l, 0, sizeof(l)); l[n]++; for (int j = i - 1; j >= 1; j--) { if (a[j] < a[i]) { tmp--; } else { tmp++; } l[tmp + n]++; } tmp = 0; ans = l[n]; for (int j = i + 1; j <= n; j++) { if (a[j] < a[i]) { tmp++; } else { tmp--; } ans += l[tmp + n]; } printf("%d", ans); if (i == n) { printf("\n"); } else { printf(" "); } } } return 0; }