欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

2020.7.15集训

程序员文章站 2022-03-14 19:37:32
...

plan

description

在小X的家乡,有机房一条街,街上有很多机房。每个机房里都有一万个人在切题。小 X 刚刷完
CodeChef\text{CodeChef},准备出来逛逛。
机房一条街有nn个机房,第 ii 个机房的坐标为 xix_i ,小 X 的家坐标为 00。小 X 在街上移动的速度为11,即从 x1x_1x2x_2 所耗费的时间为 x1x2|x_1−x_2|
每个机房的学生数量不同,ACM 题目水平也良莠不齐。小 X 到达第 ii 个机房后,可以花 tit_i 的时间
想题,然后瞬间 AK;当然,也可以过机房而不入。
小 X 现在只有 mm 个单位时间,之后他就该赶着去打 Codeforces\text{Codeforces} 了。现在他想知道自己最多能在多少个机房 AK,希望你帮帮他。

solution
发现我们一定不能往回走,所以可以按照xx坐标排个序,枚举我们最右边走到哪了,那么问题就转化成了,对于每个ii,前ii个点的tt最大的kk个要mxi\leq m-x_i,求最大的kk

那么这个东西我们可以从左往右扫描,利用权值线段树维护,每次在这个权值线段树上二分就可以了

复杂度O(nlogn)O(n\log n)

gjm写了个O(nlog2n)O(n\log^2n)的二分+堆也过了

离散化去重那里我老写不对干脆就没去重导致代码特别难看

#include <bits/stdc++.h>
using namespace std;

# define Rep(i,a,b) for(int i=a;i<=b;i++)
# define _Rep(i,a,b) for(int i=a;i>=b;i--)
# define RepG(i,u) for(int i=head[u];~i;i=e[i].next)

typedef long long ll;

const int N=1e5+5;

template<typename T> void read(T &x){
   x=0;int f=1;
   char c=getchar();
   for(;!isdigit(c);c=getchar())if(c=='-')f=-1;
   for(;isdigit(c);c=getchar())x=(x<<1)+(x<<3)+c-'0';
    x*=f;
}

# define int long long

int n,m;
int match[N];

struct node{
	int x,t;
	bool operator < (const node &cmp)const{
		return x<cmp.x;
	}
}a[N];

struct lsh{
	int val,id;
	bool operator < (const lsh &cmp)const{
		return val<cmp.val;
	}
}b[N];

int ans;

struct sakura{
	int l,r;
	int val,sum;	
}seg[N<<2];

# define lc (u<<1)
# define rc (u<<1|1)

void pushup(int u){
	seg[u].val=seg[lc].val+seg[rc].val;
	seg[u].sum=seg[lc].sum+seg[rc].sum;	
}

void build(int u,int l,int r){
	seg[u].l=l,seg[u].r=r;
	if(l==r)return;
	int mid=l+r>>1;
	build(lc,l,mid);
	build(rc,mid+1,r);	
}

void update(int u,int x,int k){
	if(seg[u].l==seg[u].r){
		seg[u].val++;
		seg[u].sum+=k;
		return;
	}
	int mid=seg[u].l+seg[u].r>>1;
	if(x<=mid)update(lc,x,k);
	else update(rc,x,k);
	pushup(u);
}

int query(int u,int k){
	if(seg[u].l==seg[u].r)return seg[u].val;	
	if(k<=seg[lc].sum)return query(lc,k);
	return seg[lc].val+query(rc,k-seg[lc].sum);
}

signed main()
{
	freopen("plan.in","r",stdin);
	freopen("plan.out","w",stdout);
	read(n),read(m);
	Rep(i,1,n)read(a[i].x),read(a[i].t),b[i]=(lsh){a[i].t,i};
	sort(a+1,a+n+1);
	sort(b+1,b+n+1);
	Rep(i,1,n)a[b[i].id].t=i,match[i]=b[i].val;
	build(1,1,n);
	Rep(i,1,n){
		update(1,a[i].t,match[a[i].t]);
		if(m>a[i].x)ans=max(ans,query(1,m-a[i].x));	
	}
	printf("%lld\n",ans);
	return 0;
}

heap

description
给定nn,问有多少个由nn的排列构成的二叉堆
注意包括小根堆和大根堆

solution
n=1n=1特判
n>1n>1只计算小根堆个数然后×2\times 2就可以了

f(i)f(i)表示ii个节点的情况数,我们可以分别算出左右子树的节点个数li,ril_i,r_i
那么有

f(i)=(i1li)f(li)f(ri)f(i)=\binom{i-1}{l_i}f(l_i)f(r_i)

然后简单递推就可以

注意不要递归会爆炸

#include <bits/stdc++.h>
using namespace std;

# pragma GCC optimize(3)

# define Rep(i,a,b) for(int i=a;i<=b;i++)
# define _Rep(i,a,b) for(int i=a;i>=b;i--)
# define RepG(i,u) for(int i=head[u];~i;i=e[i].next)

typedef long long ll;

const int N=5e6+5;
const int mod=1e9+7;

template<typename T> void read(T &x){
   x=0;int f=1;
   char c=getchar();
   for(;!isdigit(c);c=getchar())if(c=='-')f=-1;
   for(;isdigit(c);c=getchar())x=(x<<1)+(x<<3)+c-'0';
    x*=f;
}

int n;
int a[N];
int fac[N],inv[N];
int f[N],siz[N];
int ans;

int Qpow(int base,int ind){
	int res=1;
	while(ind){
		if(ind&1)res=1ll*res*base%mod;
		base=1ll*base*base%mod;
		ind>>=1;
	}
	return res;
}

# define lc (u<<1)
# define rc (u<<1|1)

int C(int n,int m){
	return 1ll*fac[n]*inv[m]%mod*inv[n-m]%mod;	
}

int main()
{
	freopen("heap.in","r",stdin);
	freopen("heap.out","w",stdout);
	read(n);
	if(n==1)return puts("1"),0;
	fac[0]=inv[0]=1;
	Rep(i,1,n)fac[i]=1ll*fac[i-1]*i%mod;
	Rep(i,1,n)inv[i]=Qpow(fac[i],mod-2);
	_Rep(u,n,1){
		siz[u]=1;
		if(lc<=n)siz[u]+=siz[lc];
		if(rc<=n)siz[u]+=siz[rc];
	}
	f[0]=f[1]=1;
	_Rep(u,n,1)
		if(siz[u]>1)
			f[siz[u]]=1ll*C(siz[u]-1,siz[lc])*f[siz[lc]]%mod*f[siz[rc]]%mod;
	printf("%lld\n",1ll*f[n]*2%mod);
	return 0;
}

road

description

因为一场不小的地震,Y 省 nn 个城市之间的道路都损坏掉了,省长希望小 X 将城市之间的道路重
修一遍。
很多城市之间的地基都被地震破坏导致不能修路了,因此可供修建的道路只有 mm 条。因为施工队伍
有限,省长要求用尽量少的道路将所有的城市连通起来,这样施工量就可以尽量少。不过,省长为了表
示自己的公正无私,要求在满足上述条件的情况下,选择一种方案,使得该方案中最贵道路的价格和最
便宜道路的价格的差值尽量小,即使这样的方案会使总价提升很多也没关系。
小 X 现在手忙脚乱,希望你帮帮他。

solution

首先根据长度排序,然后我们想到双指针,可以用lct维护连通性,复杂度O(mlogm+mlogn)O(m\log m+m\log n)

但是同样我们也可以用dfs来解决,每次找这条路径上最短的那条删掉

但是注意删掉的边要从邻接表里面跳过去,否则复杂度不对

O(mlogm+nm)O(m\log m+nm)

#include <bits/stdc++.h>
using namespace std;

# define Rep(i,a,b) for(int i=a;i<=b;i++)
# define _Rep(i,a,b) for(int i=a;i>=b;i--)
# define RepG(i,u) for(int i=head[u];~i;i=e[i].next)

typedef long long ll;

const int N=2005;
const int M=2e4+5;

template<typename T> void read(T &x){
   x=0;int f=1;
   char c=getchar();
   for(;!isdigit(c);c=getchar())if(c=='-')f=-1;
   for(;isdigit(c);c=getchar())x=(x<<1)+(x<<3)+c-'0';
    x*=f;
}

int n,m;
int head[N],cnt=1;
int ans=INT_MAX;
bool vis[N],able[M<<1];

struct sakura{
	int x,y,c;
	bool operator < (const sakura &cmp)const{
		return c<cmp.c;
	}
}e[M<<1];

struct Edge{
	int to,next,w;
}E[M<<1];

void add(int x,int y,int c){
	E[++cnt]=(Edge){y,head[x],c},head[x]=cnt;
	able[cnt]=true;
}

int dfs(int u,int tar,int pre){
	for(int i=head[u],last=0;~i;i=E[i].next){
		int v=E[i].to;
		if(!able[i]){
			if(i==head[u])head[u]=E[i].next;
			else E[last].next=E[i].next;
		}
		else{
			if(v!=pre){
				if(v==tar)return i;
				int x=dfs(v,tar,u);
				if(~x){
					if(E[i].w<E[x].w)return i;
					else return x;
				}
			}
			last=i;
		}
	}
	return -1;
}

int main()
{
	freopen("road.in","r",stdin);
	freopen("road.out","w",stdout);
	memset(head,-1,sizeof(head));
	read(n),read(m);
	Rep(i,1,m)read(e[i].x),read(e[i].y),read(e[i].c);
	sort(e+1,e+m+1);
	for(int i=1,tot=0,l=1;i<=m;i++){
		int nephren=dfs(e[i].x,e[i].y,-1);
		if(~nephren){
			tot--;
			able[nephren]=able[nephren^1]=false;
			while(l<=m&&!able[l*2])l++;
		}
		add(e[i].x,e[i].y,e[i].c);
		add(e[i].y,e[i].x,e[i].c);
		if(++tot==n-1)ans=min(ans,e[i].c-e[l].c);
	}
	printf("%d\n",ans>2e9?-1:ans);
	return 0;
}
相关标签: 比赛总结