ヒューリスティックパーティション

ヒューリスティックスプリット

    所与 n n個 数、一定の条件を点の数または最大の優先順位値、および最大量のこの点を満足するように求め ( a , b ) (A、B) セクション [ a , b ] [A、B] インターバル最大 / / 最小関連します。
    だから、あなたは間隔のために、パーティションを考慮することができます [ L , R ] [L、R] 、最小を見つけます。 / / 値に大きな
    処理サブセクションのペアを再帰的にポイントの最小/最大値を横切って処理位置

    範囲のために、最大/最小値の位置を見つけます。 m i d ミッド することができ R M Q RMQ の前処理
    と列挙 [ l , m i d ] [L、中間] [ m i d , r ] [中間、R] より小さい間隔、クエリ処理の答え


例:マルチ第十校フィールド1011メイクRounddogハッピー

効果:良い範囲は以下のように定義されます m a x ( a l , a l + 1 , . . . , a r ) ( r l + 1 ) < = k MAX(a_l、A_ {L + 1}、...、A_R) - (R - L + 1)<= K
           と間隔内全て異なる数、どのように多くの良いそこを依頼する間隔?
解決策:最大値に基づいて分割統治ヒューリスティック、 R M Q RMQ 間隔の最大値の位置の前処理しました
            L [ i ] L [i]は にあります a [ i ] [I] 、互いに異なる最も遠い位置を満たす数を左に R [ i ] R [I] 二重ポインタで右に、 O ( n ) O(N) に前処理しました

#include<bits/stdc++.h>
#define rint register int
#define deb(x) cerr<<#x<<" = "<<(x)<<'\n';
using namespace std;
typedef long long ll;
using pii = pair <int,int>;
const int maxn = 3e5 + 5;
int T, n, k, a[maxn];
int L[maxn], R[maxn], vis[maxn];
ll ans;

int dp_max[maxn][20], pos[maxn][20];
void ST(int n, int d[]) {
	for (int i=1; i<=n; i++) {
		dp_max[i][0] = d[i];
		pos[i][0] = i;
	}
	for (int j=1; (1<<j) <= n; j++) {
		for (int i=1; i+(1<<j)-1 <= n; i++) {
			if(dp_max[i][j-1] >= dp_max[i + (1<<(j-1))][j-1]) pos[i][j] = pos[i][j-1];
			else pos[i][j] = pos[i + (1<<(j-1))][j-1];
			dp_max[i][j] = max(dp_max[i][j-1], dp_max[i + (1<<(j-1))][j-1]);
		}
	}
}
int RMQ_max(int l, int r) {
	int k = 0;
	while ((1<<(k+1)) <= r-l+1) k++;
	if(dp_max[l][k] >= dp_max[r - (1<<k)+1][k]) return pos[l][k];
	else return pos[r - (1<<k)+1][k];
}

void solve(int l, int r) {
	if(l > r) return;
	int mid = RMQ_max(l, r);
	if(mid - l <= r - mid) {
		for(int i=l; i<=mid; i++) {
			int r1 = max(mid, a[mid] - k + i - 1);
			int r2 = min(r, R[i]);
			if(r1 <= r2) ans += r2 - r1 + 1;
		}
	} else {
		for(int i=mid; i<=r; i++){
			int l2 = min(mid, -a[mid] + k + i + 1);
			int l1 = max(l, L[i]);
			if(l1 <= l2) ans += l2 - l1 + 1;
		}
	}
	solve(l, mid - 1), solve(mid + 1, r);
}

int main() {
	scanf("%d", &T);
	while(T--) {
		scanf("%d%d", &n, &k);
		for(int i=1; i<=n; i++) scanf("%d", a+i);
		vis[a[1]] = 1;
		for(int i=1, p=2; i<=n; i++) {
			while(p<=n && !vis[a[p]]) vis[a[p++]] = 1;
			vis[a[i]] = 0, R[i] = p - 1;
		}
		vis[a[n]] = 1;
		for(int i=n, p=n-1; i; i--) {
			while(p && !vis[a[p]]) vis[a[p--]] = 1;
			vis[a[i]] = 0, L[i] = p + 1;
		}
		ans = 0;
		ST(n, a);
		solve(1, n);
		printf("%lld\n", ans);
	}
}

例2:羅区P4755美しいペア

効果:どのように多くの数を尋ねました a i , a j ( i < = j ) a i × a j < = m a x ( a i , a i + 1 , . . . , a j ) a_iを、a_j(I <= j)は、a_iを\回a_j <= MAX(a_iを、A_ {I + 1}、...、a_j)
解決策:最大分割に基づくヒューリスティック、列挙 a i a_iを どのように多くのセクションを見つけるために、 < = m x a i <= \ FRAC {MX} {a_iを} 数は、会長ツリーに使用することができます

#include<bits/stdc++.h>
#define rint register int
#define deb(x) cerr<<#x<<" = "<<(x)<<'\n';
using namespace std;
typedef long long ll;
const int maxn = 2e5 + 5;
int n, a[maxn], aid[maxn], tot, t[maxn*30]; 
int root[maxn*30], ls[maxn*30], rs[maxn*30];
vector <int> v;
ll ans;

int dp_max[maxn][20], pos[maxn][20];
void ST(int n, int d[]) {
	for (int i=1; i<=n; i++) {
		dp_max[i][0] = d[i];
		pos[i][0] = i;
	}
	for (int j=1; (1<<j) <= n; j++) {
		for (int i=1; i+(1<<j)-1 <= n; i++) {
			if(dp_max[i][j-1] >= dp_max[i + (1<<(j-1))][j-1]) pos[i][j] = pos[i][j-1];
			else pos[i][j] = pos[i + (1<<(j-1))][j-1];
			dp_max[i][j] = max(dp_max[i][j-1], dp_max[i + (1<<(j-1))][j-1]);
		}
	}
}
int RMQ_max(int l, int r) {
	int k = 0;
	while ((1<<(k+1)) <= r-l+1) k++;
	if(dp_max[l][k] >= dp_max[r - (1<<k)+1][k]) return pos[l][k];
	else return pos[r - (1<<k)+1][k];
}

int getid(int x){
	return lower_bound(v.begin(), v.end(), x) - v.begin() + 1;
}

void update(int &rt, int pre, int l, int r, int pos){
	if(l>pos || r<pos) return;
	rt = ++tot;
	t[rt] = t[pre] + 1;
	ls[rt] = ls[pre], rs[rt] = rs[pre];
	if(l == r) return;
	int m = l + r >> 1;
	update(ls[rt], ls[pre], l, m, pos);
	update(rs[rt], rs[pre], m+1, r, pos);
}

int query(int rt, int pre, int l, int r, int pos){
	if(l > pos) return 0;
	if(r <= pos) return t[rt] - t[pre];
	int m = l + r >> 1, ret = 0;
	ret += query(ls[rt], ls[pre], l, m, pos);
	ret += query(rs[rt], rs[pre], m+1, r, pos);
	return ret;
}

void solve(int l, int r){
	if(l > r) return;
	int pos = RMQ_max(l, r), mx = a[pos];
	if(pos - l <= r - pos){
		for(int i=l; i<=pos; i++){
			int k = mx / a[i];
			int kid = upper_bound(v.begin(), v.end(), k) - v.begin();
			ans += query(root[r], root[pos-1], 1, v.size(), kid);
		}
	} else {
		for(int i=pos; i<=r; i++){
			int k = mx / a[i];
			int kid = upper_bound(v.begin(), v.end(), k) - v.begin();
			ans += query(root[pos], root[l-1], 1, v.size(), kid);
		}
	}
	solve(l, pos - 1), solve(pos + 1, r);
}

int main() {
	scanf("%d", &n);
	for(int i=1; i<=n; i++) scanf("%d", a+i), v.push_back(a[i]);
	v.push_back(1e9 + 7);
	sort(v.begin(), v.end());
	v.erase(unique(v.begin(), v.end()), v.end());
	for(int i=1; i<=n; i++){
		aid[i] = getid(a[i]);
		update(root[i], root[i-1], 1, v.size(), aid[i]);
	}
	ST(n, a);
	solve(1, n);
	printf("%lld\n", ans);
}
发布了221 篇原创文章 · 获赞 220 · 访问量 2万+

おすすめ

転載: blog.csdn.net/Scar_Halo/article/details/103821331