1. 程式人生 > 實用技巧 >2020CCPC 秦皇島 E題

2020CCPC 秦皇島 E題

這個題可以尺取也可以權值線段樹,我選擇了權值線段樹動態開點

我是sb

把陣列按照a排序

1.如果沒有人選a,那麼分數線就按照b的最大值算

2.如果選了ai,那比ai小的aj都要選(貪心)

3.數字很大記得動態開點

沒事了

非常可惜,其實我已經想到一半以上了,可惜看錯了題。。。。秦皇島兩個銅題都很簡單,非常可惜,如果多給我門一個小時說不定。。。。

#include<iostream>

#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
typedef long long ll;
const int maxn = 6e7+111;
struct Node{
	int x,y;
}que[maxn];

int cnt = 0;

struct node{
	int l,r,ans;
}tree[maxn];


int update(int& node,int be,int en,int i,int val){
	if(node == 0) node = ++cnt;
	int mid = be + en >> 1;
	if(be == en){
		tree[node].ans += val;
		return 0;
	}
	if(i <= mid) update(tree[node].l,be,mid,i,val);
	else update(tree[node].r,mid+1,en,i,val);
	
	int l = tree[node].l;
	int r = tree[node].r;
	
	tree[node].ans = tree[l].ans + tree[r].ans;
	return 0;
}

int ask(int node,int be,int en,int LL,int RR){
	if(node == 0) return 0;
	
	int mid = be + en >> 1;
	if(LL <= be && en <= RR){
		return tree[node].ans;
	}
	int val1 = 0,val2 = 0;
	if(LL <= mid) val1 = ask(tree[node].l,be,mid,LL,RR);
	if(RR > mid) val2 = ask(tree[node].r,mid+1,en,LL,RR);
    
	return val1 + val2;
}
int vis[500050];

bool bml(Node a,Node b){
	return a.x > b.x;
}


int main(){
	int t;
	int aa = 0;
	scanf("%d",&t);
	
	while(t--){
		int n;
		double p;
		scanf("%d%lf",&n,&p);
		p/=100;
		
		int len = 0;
		cnt = 2;
		int root = 1;
		
		
		int nn = 2e9;
		
		for(int i=0;i<n;i++){
			scanf("%d %d",&que[i].x,&que[i].y);			
		}
		sort(que,que+n,bml);
		int mx = -1;
		for(int i=0;i<n;i++){
			update(root,1,nn,que[i].x,1);
		}
		int ans = 0;
		
		
		for(int i=0;i<n;i++){
			int cns;
			if(que[i].x > mx){
				int r = ceil(1.0*que[i].x*p);
				cns = ask(root,1,nn,r,que[i].x);
			}
			else{
				int r = ceil(1.0*mx*p);
				cns = ask(root,1,nn,r,mx);
			}
			ans = max(ans,cns);
			
			update(root,1,nn,que[i].y,1);	
			update(root,1,nn,que[i].x,-1);
			mx = max(mx,que[i].y);
		}
		int r = ceil(1.0*mx*p);
		int	cns = ask(root,1,nn,r,mx);
		ans = max(ans,cns);
		
		
		for(int i=0;i<=cnt;i++){
			tree[i].ans = tree[i].l = tree[i].r = 0;
		}
		cnt = 0;
		printf("Case #%d: %d\n",++aa,ans);
		
	}
	return 0;
}

提供一種類似尺取的寫法,記得所有人都在的時候才能算入答案

這個更騷

#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
const int maxn = 6e7+111;
struct Node{
	int val;
	int id;
}que[maxn];
bool bml(Node a,Node b){
	return a.val < b.val;
}
int cnt = 0;
struct node{
	int l,r,ans;
}tree[maxn];
int update(int& node,int be,int en,int i,int val){
	if(node == 0) node = ++cnt;
	int mid = be + en >> 1;
	if(be == en){
		tree[node].ans += val;
		return 0;
	}
	if(i <= mid) update(tree[node].l,be,mid,i,val);
	else update(tree[node].r,mid+1,en,i,val);
	int l = tree[node].l;
	int r = tree[node].r;
	
	tree[node].ans = tree[l].ans + tree[r].ans;
	return 0;
}
int ask(int node,int be,int en,int LL,int RR){
	if(node == 0) return 0;
	int mid = be + en >> 1;
	if(LL <= be && en <= RR){
		return tree[node].ans;
	}
	int val1 = 0,val2 = 0;
	if(LL <= mid) val1 = ask(tree[node].l,be,mid,LL,RR);
	if(RR > mid) val2 = ask(tree[node].r,mid+1,en,LL,RR);
	return val1 + val2;
}
int vis[200050];

int main(){

	int t;
	int aa = 0;
	scanf("%d",&t);
	while(t--){
		int n;
		double p;
		scanf("%d %lf",&n,&p);
		p/=100;
		int len = 0;
		cnt = 2;
		int root = 1;
		
		for(int i=1;i<=n;i++){
			int a,b;
			scanf("%d%d",&a,&b);
			vis[i] = 0;
			que[len].val = a;
			que[len].id = i;
			len++;
			que[len].val = b;
			que[len].id = i;
			len++;
		}
		int nn = 1e9 + 11111;
		
		sort(que,que+len,bml);
		
		int ans = 0;
		int cnn = 0;
		
		for(int i=0;i<len;i++){
			if(vis[que[i].id] != 0){
				update(root,1,nn,vis[que[i].id],-1);
			}
			update(root,1,nn,que[i].val,1);
			if(vis[que[i].id] == 0)	cnn++;
			
			
			vis[que[i].id] = que[i].val;
			double c = que[i].val;
			int r = c * p + 0.99999;
			
			int cns = ask(root,1,nn,r,que[i].val);
			if(cnn == n) ans = max(ans,cns);
		}
		
		
		for(int i =0 ;i<=cnt;i++){
			tree[i].l = tree[i].r = tree[i].ans = 0;
		}
		cnt = 2;
		printf("Case #%d: %d\n",++aa,ans);
	}
	return 0;
}