第一次icpc集訓(wednesday)

總結

這次的比賽總的來說並不算,排名接近墊底。總的來說,原因可以分爲兩個方面:1、比賽開頭並沒有打好,簽到題wa了兩次,模擬題沒有迅速拿下2、隊伍配合方面尚需要磨合,由於是第一次打配合,每個人的優勢並沒有得到充分的顯現。3、就本人而言,太久沒有搞競賽算法敏感度和實現能力均有所下降,該切的題目沒切下來,a想到正解的時間有點長,e想到二分結果分錯了東西心態都崩了
綜上所述,這次的比賽代表意義並不太大,屬於開始的波動期。

A Circuits(掃描線+線段樹維護)

description

給定n個矩形,求兩條水平直線能與之相交的最大矩形數量(n<=1e5)

solution

拿到題目一看,貪心(想peach)?這種一眼是貪心的一開始沒什麼人打的就不應該是貪心!我們考慮枚舉其中一條水平線的位置,那麼剩下的矩形只有不跨過水平線的矩形,用線段樹維護左右兩端縱座標
被剩下的矩形覆蓋的數量,這個用掃描線解決。時間複雜度O(NlogN)

code

#include<iostream>
#include<cmath>
#include<cstring>
#include<cstdio>
#include<algorithm>
#define ll long long
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define rp(i,a,b) for(int i=a;i>=b;i--)
#define max(a,b) ((a>b)?a:b)
#define min(a,b) ((a<b)?a:b)
using namespace std;
const int maxn=2e5+5;
struct code{
	int x,y,z;
}a[maxn],c[maxn];
int bz[maxn*4],b[maxn],f[maxn*4],lef[maxn],rig[maxn];
int num,n,m,i,j,k,l,ans,t,x,y,z;
bool cmp(code x,code y){
	return x.x<y.x || x.x==y.x && x.z<y.z;
}
bool cmp1(code x,code y){
	return x.y<y.y;
}
bool cmp2(code x,code y){
	return x.x>y.x;
}
void make(int l,int r,int v,int x,int y){
	int mid=(l+r)/2;
	if (bz[v] && l!=r){
		f[v*2]+=bz[v];f[v*2+1]+=bz[v];bz[v*2]+=bz[v];bz[v*2+1]+=bz[v];
		bz[v]=0;
	}
	if (l>=x && r<=y){
		f[v]++;bz[v]++;return;
	}
	if (mid>=x) make(l,mid,v*2,x,y); 
	if (mid<y) make(mid+1,r,v*2+1,x,y);
	f[v]=max(f[v*2],f[v*2+1]);
}
int main(){
	freopen("data.in","r",stdin);
	freopen("data.out","w",stdout);
	scanf("%d",&n);
	fo(i,1,n){
		scanf("%d%d%d%d",&x,&y,&z,&k);
		if (y>k)swap(y,k);
		a[++num]={y,i,0};a[++num]={k,i,1};
	}
	sort(a+1,a+n*2+1,cmp);num=0;a[0].x=-1e9;
	fo(i,1,n*2){
		if (a[i].x!=a[i-1].x) num++;
		if (b[i]>b[t]) t=i;
		if (a[i].z) c[a[i].y].y=num;
		else c[a[i].y].x=num;
	}
	fo(i,1,n) b[c[i].x]++,b[c[i].y+1]--;
	sort(c+1,c+n+1,cmp1);
	j=1;num++;
	fo(i,1,num){
		b[i]+=b[i-1];
		while (c[j].y<i && j<=n){
			make(1,num,1,c[j].x,c[j].y);
			j++;
		}
		lef[i]=f[1];
	}
	memset(f,0,sizeof(f));memset(bz,0,sizeof(bz));
	sort(c+1,c+n+1,cmp2);
	j=1;
	rp(i,num-1,1){
		while (c[j].x>i && j<=n){
			make(1,num,1,c[j].x,c[j].y);
			j++;
		}
		rig[i]=f[1];
	}
	fo(i,1,num) 
		ans=max(ans,b[i]+max(lef[i],rig[i]));
	printf("%d\n",ans);
}

B Cosmetic Survey(floyd)

description

n個人各自給定m個物體的優先級順序(可以平級,可以評0表示最後),定義d(x,y)表示認爲x比y優的人的數量,規定x比y優當存在一條路徑a1(x),a2,……,an(y)滿足d(ai,ai+1)>d(ai+1,ai),並這條路徑最小的d(ai,ai+1)爲這條路徑的權,定義S(X,Y)爲所有x到y路徑中最大的權,定義x爲最優當且僅當所有y均滿足S(X,Y)>=s(Y,X),輸出所有最優點x(n,m<=500)

solution

<=500,路徑,floyd安排上,求出所有的S(X,Y)。

code

#include<bits/stdc++.h>
using namespace std;
int n,m,d[510][510],s[510][510],path[510][510];
int main(){
	cin>>n>>m;
	for(int i=1;i<=n;i++)
	  for(int j=1;j<=n;j++)
	    {
	    	d[i][j]=0;
	    	path[i][j]=0;
		}
	for(int i=1;i<=m;i++)
	  for(int j=1;j<=n;j++){
	  	 scanf("%d",&s[i][j]);
	  	 if(s[i][j]==0) s[i][j]=1e9+10;
	  }
	for(int i=1;i<=m;i++){
		 for(int j=1;j<=n;j++)
		    for(int k=j+1;k<=n;k++){
		    	if(s[i][j]<s[i][k]) d[j][k]++;
		    	if(s[i][k]<s[i][j]) d[k][j]++;
			}
	}
	for(int i=1;i<=n;i++)
	   for(int j=i+1;j<=n;j++)
	      if(d[i][j]>d[j][i]) path[i][j]=d[i][j];
	      else if(d[j][i]>d[i][j]) path[j][i]=d[j][i];
	for(int k=1;k<=n;k++)
	  for(int i=1;i<=n;i++)
	     for(int j=1;j<=n;j++)
	     if(path[i][k]!=0&&path[k][j]!=0)
		   path[i][j]=max(path[i][j],min(path[i][k],path[k][j]));      
	for(int i=1;i<=n;i++){
		int flag=1;
		for(int j=1;j<=n;j++)
		  if(i!=j&&path[i][j]<path[j][i]) flag=0;
		if(flag) cout<<i<<" ";
	}
	return 0; 
}

D,F模擬題,pass

E LED(二分答案)

description

定義F(vi)函數
在這裏插入圖片描述
在這裏插入圖片描述
V是電壓 L是亮度,其中0<V1<V2,0<=L1<=L2
給你n(n<=3e5)組實驗數據(li,vi),需要求出一個F(vi)函數使得誤差最小。
在這裏插入圖片描述

solution

一開始吧max看成sigma的我果然有問題?然後開心的安排了棵主席樹,枚舉V1位置二分V2位置,從此離正解越來越遠……後面發現了是max後,把主席樹刪了少了個log,但還是沒想到“二分答案”!!!
加入一開始就看到max,二分答案不就自然而然出來了嗎?我們二分誤差值,然後左邊V1取到極限情況後第二條繼續取(可以發現一堆數中最小的誤差值就是取在最大值與最小值平均數的位置),然後第三條,注意判L1<=L2,還有vi=0的數據,在y軸上的數據是不可能在第二條線上的,因此要特殊處理。

code

#include<iostream>
#include<cmath>
#include<cstring>
#include<cstdio>
#include<algorithm>
#define ll long long
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define rp(i,a,b) for(int i=a;i>=b;i--)
#define max(a,b) ((a>b)?a:b)
#define min(a,b) ((a<b)?a:b)
using namespace std;
const int maxn=3e5+5;
const int mo=1e9;
struct code{
	int x,y;
}a[maxn];
int num,n,m,i,j,k,t,x,y,z,mx,mi,num1,ln;
int d[maxn];
double ans,p,l,r,mid;
bool cmp(code x,code y){
	return x.x<y.x;
}
int main(){
	//freopen("data.in","r",stdin);
	//freopen("data.out","w",stdout);
	scanf("%d",&n);char ch;
	fo(i,1,n)scanf("%d%d",&a[i].x,&a[i].y);
	sort(a+1,a+n+1,cmp);l=0;
	for(i=1;!a[i].x;i++)l=max(l,a[i].y);
	r=1e9;
	while (r-l>0.01){
		mid=(l+r)/2;
		for (i=1;i<=n && a[i].y<=mid;i++);
		mi=1e9;mx=0;
		for (;i<=n;i++){
			t=mx+mi;
			mx=max(mx,a[i].y),mi=min(mi,a[i].y);
			if (mx-mi>mid*2) break;
		}
		if (i>n){
			r=mid;continue;
		}
		mi=1e9;mx=0;
		for (;i<=n;i++){
			mx=max(mx,a[i].y),mi=min(mi,a[i].y);
			if (mx-mi>mid*2) break;
		}
		k=mx+mi;
		if (i<=n || t>k) l=mid;
		else r=mid;
	}
	printf("%.1lf\n",l);
}

L workingplan(貪心+優先隊列)

description

有n天,m個工人,他們一旦工作就要連續工作w天,然後需要休息h天。然後每個工人需要工作wi天,其中這個wi天是需要能被w天整除的。最後是n天,每一天需要的工人數目di。(n,m<=2000)

solution

貪心+優先隊列,維護一個按需要工作排序的可工作隊列和一個按可以工作的時間的不可工作隊列

code

#include<iostream>
#include<queue>
#include<cstdio>

using namespace std;
int read() {
	int f = 1, s = 0; char c = getchar();
	for (; c < '0' || c>'9'; c = getchar())if (c == '0')f = -1;
	for (; c >= '0' && c <= '9'; c = getchar())s = s * 10 + c - 48;
	return f * s;
}
const int N = 2010;
struct qq {
	int id;
	int days;
}t;
struct qqq {
	qq p;
	int remains;
}tt;
bool operator <(qq a, qq b) {
	return a.days < b.days;
}
bool operator <(qqq a, qqq b) {
	return a.remains > b.remains;
}
vector<int>ans[N];
int m, n, w, h;
int a[N];
bool work() {
	m = read(); n = read(); w = read(); h = read();
	if (w > n)return 0;
	priority_queue<qq>q;
	priority_queue<qqq>qt;
	for (int i = 1; i <= m; i++) {
		t.id = i;
		t.days = read();
		if (t.days % w)return 0;
		t.days /= w;
		if (t.days)q.push(t);
	}
	for (int i = 1; i <= n; i++)a[i] = read();
	for (int i = 1; i + w - 1 <= n; i++) {
		while (qt.size() && qt.top().remains == i) {
			q.push(qt.top().p);
			qt.pop();
		}
		if (a[i] == 0)continue;

		for (int j = i + 1; j <= i + w - 1; j++) {
			a[j] -= a[i];
			if (a[j] < 0)return 0;
		}
		while (a[i]) {
			if (q.size() == 0)return 0;
			t = q.top(); q.pop();
			ans[t.id].push_back(i);
			t.days--;
			if (t.days) {
				tt.p = t;
				tt.remains = i + w + h ;
				qt.push(tt);
			}
			a[i]--;
		}
	}
	for (int i = n - w; i <= n; i++)if (a[i])return 0;
	return 1;
}
int main() {
	if (work() == 0)printf("-1");
	else {
		printf("1\n");
		for (int i = 1; i <= m; i++) {
			for (int j = 0; j < ans[i].size(); j++)
				printf("%d ", ans[i][j]);
			printf("\n");
		}
	}
	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章