第一次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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章