5696 区间的价值
对于一个区间,考虑最小的数做出的贡献。对于最小的数,一定是和最大的数组成的对数才能对答案产生影响,否则对答案是没有作用的。所以就可以从最小值的位置,把整个区间分裂成两段,然后再递归下去。每次需要找个区间最小值,然后最靠近最小值的区间最大值,然后每个区间可以找到个答案对答案区间产生影响,所以我当时就写了三个线段树。。这样的话整个的复杂度应该是nlognlogn的,然后由于数据是随机的。所以他们都是直接区间暴力找。。复杂度大概是nlogn的。
//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<vector>
#include<cmath>
#include<queue>
#include<stack>
#include<set>
#include<map>
#define xx first
#define yy second
#define LL long long
#define MP make_pair
#define inf 0x3f3f3f3f
#define CLR(a, b) memset(a, b, sizeof(a))
#define lson l, m, rt << 1
#define rson m + 1, r, rt << 1 | 1
using namespace std;
const int maxn = 100100;
struct SegTree1 {
LL seg[maxn << 2], mark[maxn << 2];
void up(int rt) {
seg[rt] = max(seg[rt << 1], seg[rt << 1 | 1]);
}
void build(int l, int r, int rt) {
seg[rt] = 0; mark[rt] = 0;
if(l == r) return ;
int m = (l + r) >> 1;
build(lson);
build(rson);
}
void update(int L, int R, LL v, int l, int r, int rt) {
if(L <= l && r <= R) {
mark[rt] = max(mark[rt], v);
seg[rt] = max(seg[rt], v);
return ;
}
int m = (l + r) >> 1;
if(L <= m) update(L, R, v, lson);
if(R > m) update(L, R, v, rson);
up(rt);
}
LL query(int p, int l, int r, int rt) {
if(l == r) {
return seg[rt];
}
int m = (l + r) >> 1;
LL ret = mark[rt];
if(p <= m) ret = max(ret, query(p, lson));
else ret = max(ret, query(p, rson));
return ret;
}
} seg1;
int a[maxn];
struct SegTree2 {
int seg[maxn << 2];
void up(int rt) {
if(a[seg[rt << 1]] <= a[seg[rt << 1 | 1]]) seg[rt] = seg[rt << 1];
else seg[rt] = seg[rt << 1 | 1];
}
void build(int l, int r, int rt) {
if(l == r) {
seg[rt] = l;
return ;
}
int m = (l + r) >> 1;
build(lson);
build(rson);
up(rt);
}
int query(int L, int R, int l, int r, int rt) {
if(L <= l && r <= R) {
return seg[rt];
}
int m = (l + r) >> 1;
int ret = -1;
if(L <= m) {
ret = query(L, R, lson);
};
if(R > m) {
int c = query(L, R, rson);
if(ret == -1 || a[ret] > a[c])
ret = c;
}
return ret;
}
} seg2;
struct SegTree3 {
int segl[maxn << 2], segr[maxn << 2];
void up(int rt) {
if(a[segl[rt << 1]] >= a[segl[rt << 1 | 1]]) segl[rt] = segl[rt << 1];
else segl[rt] = segl[rt << 1 | 1];
if(a[segr[rt << 1 | 1]] >= a[segr[rt << 1]]) segr[rt] = segr[rt << 1 | 1];
else segr[rt] = segr[rt << 1];
}
void build(int l, int r, int rt) {
if(l == r) {
segr[rt] = segl[rt] = l;
return ;
}
int m = (l + r) >> 1;
build(lson);
build(rson);
up(rt);
}
int queryl(int L, int R, int l, int r, int rt) {
if(L <= l && r <= R) {
return segl[rt];
}
int m = (l + r) >> 1;
int ret = -1;
if(L <= m) {
ret = queryl(L, R, lson);
}
if(R > m) {
int c = queryl(L, R, rson);
if(ret == -1 || a[ret] < a[c])
ret = c;
}
return ret;
}
int queryr(int L, int R, int l, int r, int rt) {
if(L <= l && r <= R) {
return segr[rt];
}
int m = (l + r) >> 1;
int ret = -1;
if(R > m) {
ret = queryr(L, R, rson);
}
if(L <= m) {
int c = queryr(L, R, lson);
if(ret == -1 || a[ret] < a[c])
ret = c;
}
return ret;
}
} seg3;
int n;
void dfs(int l, int r) {
if(l > r) return ;
int mi = seg2.query(l, r, 1, n, 1);
int mx = seg3.queryl(mi, r, 1, n, 1);
int mx2 = seg3.queryr(l, mi, 1, n, 1);
LL vv = 1ll * a[mi] * a[mx];
int mxl = mx - mi + 1;
if(a[mx2] > a[mx] || (a[mx2] == a[mx] && (mi - mx2 > mx - mi))) {
mxl = mi - mx2 + 1;
vv = 1ll * a[mi] * a[mx2];
}
seg1.update(mxl, r - l + 1, vv, 1, n, 1);
dfs(l, mi - 1);
dfs(mi + 1, r);
}
int main() {
while(scanf("%d", &n) != EOF) {
for(int i = 1; i <= n; i ++) {
scanf("%d", &a[i]);
}
seg2.build(1, n, 1);
seg1.build(1, n, 1);
seg3.build(1, n, 1);
dfs(1, n);
for(int i = 1; i <= n; i ++) {
printf("%I64d\n", seg1.query(i, 1, n, 1));
}
}
return 0;
}
5698 瞬间移动
这题,可以考虑到,dp[n][m] = sum(dp[i][j])(i<n&&j<m),然后化简一下。。大概就是C(n-2, n-2+m-2)。
#pragma comment(linker, "/STACK:102400000000,102400000000")
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<vector>
#include<cmath>
#include<queue>
#include<stack>
#include<set>
#include<map>
#define xx first
#define yy second
#define LL long long
#define MP make_pair
#define INF 0x3f3f3f3f
#define lson l, m, rt << 1
#define rson m + 1, r, rt << 1|1
#define CLR(a, b) memset(a, b, sizeof(a))
using namespace std;
const int maxn = 200100;
const int MOD = 1000000007;
int A[maxn];
void init() {
A[0] = A[1] = 1;
for(int i = 2; i < maxn; i ++) {
A[i] = 1ll * A[i - 1] * i % MOD;
}
}
int Inv(int a) {
int ret = 1, n = MOD - 2;
while(n) {
if(n & 1) ret = 1ll * ret * a % MOD;
a = 1ll * a * a % MOD;
n >>= 1;
}
return ret;
}
int C(int m, int n) {
return 1ll * A[n] * Inv(A[m]) % MOD * Inv(A[n - m]) % MOD;
}
int main() {
init();
int n, m;
while(scanf("%d%d", &n, &m) != EOF) {
n -= 2; m -= 2;
printf("%d\n", C(n, n + m));
}
return 0;
}
这题其实是要找所有可以由k个区间交出来的区间,然后计算一下所有这种区间的最大值。然后就可以对于现在的区间先排序,然后依次加入到队列中,然后当超过k个之后,需要把右端点最小的删掉,因为这个对于当前相交区间的影响是最不好的。于是这样维护一下就好了。
//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<vector>
#include<cmath>
#include<queue>
#include<stack>
#include<set>
#include<map>
#define xx first
#define yy second
#define LL long long
#define MP make_pair
#define inf 0x3f3f3f3f
#define CLR(a, b) memset(a, b, sizeof(a))
#define lson l, m, rt << 1
#define rson m + 1, r, rt << 1 | 1
using namespace std;
const int maxn = 100100;
pair<int, int> seg[maxn];
int a[maxn];
LL sum[maxn];
int main() {
int n, k, m;
while(scanf("%d%d%d", &n, &k, &m) != EOF) {
sum[0] = 0;
for(int i = 1; i <= n; i ++) {
scanf("%d", &a[i]);
sum[i] = sum[i - 1] + a[i];
}
for(int i = 0; i < m; i ++) {
scanf("%d%d", &seg[i].xx, &seg[i].yy);
}
sort(seg, seg + m);
map<int, int> L, R;
priority_queue<pair<int, int> > Q;
int l = 1;
LL ans = 0;
for(int i = 0; i < m; i ++) {
Q.push(MP(-seg[i].yy, seg[i].xx));
L[seg[i].xx] ++;
R[seg[i].yy] ++;
if(Q.size() > k) {
pair<int, int> p = Q.top(); Q.pop();
L[p.yy] --;
if(L[p.yy] == 0) L.erase(p.yy);
R[-p.xx] --;
if(R[-p.xx] == 0) R.erase(-p.xx);
}
if(Q.size() == k) {
int l = (*L.rbegin()).first, r = (*R.begin()).first;
if(r >= l) ans = max(ans, sum[r] - sum[l - 1]);
}
}
printf("%I64d\n", ans);
}
return 0;
}
5701 中位数计数
这题直接n^2暴力就好了。枚举每个数作为中位数,由于数字都不一样,所以只能是总共是奇数个数。于是考虑对于当前数,我们可以把小于他的位置设为-1,大于的设为1,那么包含当前数字区间和为0的区间是满足的。于是维护一下就好了。
//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<vector>
#include<cmath>
#include<queue>
#include<stack>
#include<set>
#include<map>
#define xx first
#define yy second
#define LL long long
#define MP make_pair
#define INF 0x3f3f3f3f
#define lson l, m, rt << 1
#define rson m + 1, r, rt << 1|1
#define CLR(a, b) memset(a, b, sizeof(a))
using namespace std;
const int maxn = 8080;
int a[maxn], cnt[maxn * 2], b[maxn];
int main() {
int n;
while(scanf("%d", &n) != EOF) {
for(int i = 1; i <= n; i ++) {
scanf("%d", &a[i]);
}
for(int i = 1; i <= n; i ++) {
b[0] = n;
int ans = 0;
CLR(cnt, 0);
cnt[n] = 1;
for(int j = 1; j <= n; j ++) {
if(a[j] > a[i]) b[j] = 1;
else if(a[j] < a[i]) b[j] = -1;
else b[j] = 0;
b[j] += b[j - 1];
if(j < i) {
cnt[b[j]] ++;
}
if(j >= i) {
ans += cnt[b[j]];
}
}
printf("%d%c", ans, i == n ? '\n' : ' ');
}
}
return 0;
}