1. 程式人生 > >Codeforces Round #419 (Div. 1) 補題 CF 815 A-E

Codeforces Round #419 (Div. 1) 補題 CF 815 A-E

pac 三元組 題意 pan codeforce names bre d+ cmp

A-C傳送門

D Karen and Cards

技巧性很強的一道二分優化題

題意很簡單 給定n個三元組,和三個維度的上限,問存在多少三元組,使得對於給定的n個三元組中的每一個,必有兩個維度嚴格小於。

首先我們根據一個維度(c維)對n個三元組排序,然後枚舉答案在這個維度的取值。

此時序列被分成了兩個部分,前半部分 滿足所有c大於等於i 後半部分滿足所有c嚴格小於i(即已有一個維度小於)

通過累計,我們知道此時前半部a維的最大值ma和b維的最大值mb.

顯然可能存在的三元組答案,必然首先滿足a維和b維嚴格大於ma和mb.

後面我們考慮對於後半部分,即c嚴格小於i的部分,可能存在某些三元組 ai和bi非常大,以致於上邊的答案不合法。

這時,我們想知道,對於ai大於ma的那些三元組,其對應的bi能有多大?

我們可以用一個mx數組提前統計這個值。

那麽,當ai大到一定程度,其對應的bi就不可能大於mb了 我們可以二分找到這個邊界ret

對於ma到ret這個範圍的值,我們讓第一維取其中的某個值,對應的第二維b有多少種可能呢?

所有ai大於當前值的對應的bi的最大值。 因為若ai小於當前值,就不需要保證第二維大於bi了。。

具體看代碼吧 有點難以描述。

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,a,b) for(int i=a;i>=b;i--)
#define maxn 500005
#define ll long long
using namespace std;

ll sum[maxn],mx[maxn];

ll n,p,q,r;

ll ans;

struct note{
	int a,b,c;
}a[maxn];

bool cmp(note i,note j){
	return i.c>j.c;
}

int main(){
	scanf("%I64d%I64d%I64d%I64d",&n,&p,&q,&r);
	fo(i,1,n) scanf("%d%d%d",&a[i].a,&a[i].b,&a[i].c);
	fo(i,1,n) mx[a[i].a]=max(mx[a[i].a],(ll)a[i].b+1);
	fd(i,p,1) mx[i]=max(mx[i+1],mx[i]);//可能存在的最大b值 
	fo(i,1,p) sum[i]=sum[i-1]+(q-mx[i])+1;
	ll ma=1,mb=1;
	sort(a+1,a+n+1,cmp);
	int wz=1;
	fd(i,r,1) {
		while (wz<=n && a[wz].c==i) {
			ma=max(ma,a[wz].a+1ll);
			mb=max(mb,a[wz].b+1ll);
			wz++;
		}
		if (ma>p || mb>q) break;
		int x=ma,y=p,ret=ma-1;
		while (x<=y) {
			int mid=(x+y) >> 1;
			if (mx[mid]>=mb) {
				x=mid+1;
				ret=mid;
			}
			else y=mid-1;
		}
		ans+=sum[ret]-sum[ma-1]+1ll*(p-ret)*(q-mb+1);
	}
	cout<<ans;
	return 0;
}

E Karen and Neighborhood

Codeforces Round #419 (Div. 1) 補題 CF 815 A-E