【模拟赛】20200614

题意/题解

T1 序列合并

  • 题意:给你两个序列,你可以从两个序列中各挑一个数相加,找出前 \(n\) 小的,保证序列递增。
  • 题解:优先队列,一开始把两个序列首的和以及构成这个数的两个数在各自序列中的坐标 \(l,r\) 放进去(这一定是最小的),然后输出的时候将队首取出,然后把 \(l,r+1\)\(l+1,r\) 放进去,这样取 \(n\) 次。

T2 扩散

  • 题意:有 \(n\) 个点,每个点每一各单位时间就向四个方向扩散一个单位,问你最少多长时间按后变成一个联通块
  • 题解:算出每两个点多长时间后会变成一个联通块,将这个作为他们的距离,然后跑最小生成树,找到最大的边就是答案。

C 进攻策略

  • 题意:有 \(n\) 个需要攻略的单位排成一列击破第 \(i\) 个点需要的攻击力和为 \(q_i\),有 \(m\) 种攻击手段,第 \(i\) 种手段有 \(a_i\) 的攻击力,\(c_i\) 的花费,你最多可以花费 \(k\),问你最多可以击破几个相邻的点。
  • 题解:背包+前缀和+二分。用背包求出当花费为 \(l\) 是能提供的最大攻击力,然后计算击破每个点的最小花费求个前缀和,二分答案,check的时候枚举区间的一个端点用前缀和求花费。

代码

T1 序列合并

#include<cstdio>
#include<cstring>
#include<string>
#include<iostream>
#include<algorithm>
#include<queue>
#include<map>
#define MAXN 100001

inline void read(int &T) {
	int x=0;bool f=0;char c=getchar();
	while(c<'0'||c>'9'){if(c=='-')f=!f;c=getchar();}
	while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
	T=f?-x:x;
}

struct ppair{
	int w,l,r;
	friend bool operator<(ppair x,ppair y) {
		return x.w>y.w;
	}
};
std::priority_queue<ppair> q;
std::map<int,bool> map[MAXN];
int n,a[MAXN],b[MAXN];

int main() {
	//freopen("sequence.in","r",stdin);
	//freopen("sequence.out","w",stdout);
	read(n);int okay=n;
	for(int i=1;i<=n;++i) read(a[i]);
	for(int i=1;i<=n;++i) read(b[i]);
	q.push((ppair){a[1]+b[1],1,1});
	while(!q.empty()&&okay) {
		ppair pos=q.top();
		printf("%d ",pos.w);
		if(pos.r+1<=n&&!map[pos.l][pos.r+1]) {
			map[pos.l][pos.r+1]=1;
			q.push((ppair){a[pos.l]+b[pos.r+1],pos.l,pos.r+1});
		}
		if(pos.l+1<=n&&!map[pos.l+1][pos.r]) {
			map[pos.l+1][pos.r]=1;
			q.push((ppair){a[pos.l+1]+b[pos.r],pos.l+1,pos.r});
		}
		q.pop();
		--okay;
	}
	fclose(stdin),fclose(stdout);
	return 0;
}

T2 扩散

#include<cmath>
#include<cstdio>
#include<cstring>
#include<string>
#include<iostream>
#include<algorithm>
#define MAXN 1001

inline void read(int &T) {
	int x=0;bool f=0;char c=getchar();
	while(c<'0'||c>'9'){if(c=='-')f=!f;c=getchar();}
	while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
	T=f?-x:x;
}

int n,cnt,x[MAXN],y[MAXN];
int fa[MAXN],size[MAXN];
struct Edge {
	int u,v,w;
	friend bool operator<(Edge a,Edge b) {
		return a.w<b.w;
	}
}pth[1001*1000*2];

int find(int x) {
	return fa[x]==x?x:find(fa[x]);
}

void Union(int a,int b) {
	int roota=find(a),rootb=find(b);
	if(size[roota]>size[rootb]) {
		fa[rootb]=roota;
		size[roota]+=size[rootb];
	}else {
		fa[roota]=rootb;
		size[rootb]+=size[roota];
	}
}

int main() {
	//freopen("spread.in","r",stdin);
	//freopen("spread.out","w",stdout);
	read(n);
	for(int i=1;i<=n;++i) read(x[i]),read(y[i]);
	for(int i=1;i<=n;++i) {
		for(int j=1;j<=n;++j) {
			pth[++cnt].u=i,pth[cnt].v=j;
			pth[cnt].w=(abs(y[j]-y[i])+abs(x[j]-x[i])+1)/2;
		}
	}
	for(int i=1;i<=n;++i) fa[i]=i;
	std::sort(pth+1,pth+cnt+1);
	int ub=n-1;
	for(int i=1;i<=cnt;++i) {
		if(find(pth[i].u)!=find(pth[i].v)) {
			Union(pth[i].u,pth[i].v);
			--ub;
			if(ub==0) printf("%d\n",pth[i].w);
		}
	}
	fclose(stdin),fclose(stdout);
	return 0;
}

T3 进攻策略

#include<cstdio>
#include<cstring>
#include<string>
#include<iostream>
#include<algorithm>
#define MAXN 200001

inline void read(int &T) {
	int x=0;bool f=0;char c=getchar();
	while(c<'0'||c>'9'){if(c=='-')f=!f;c=getchar();}
	while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
	T=f?-x:x;
}

int n,m,k,q[MAXN],sum[MAXN];
long long coast[MAXN];
long long dp[1001];
struct z {
	int c,a;
}zz[101];

/*bool count(int l,int r) {
	int x=k;
	for(int i=l;i<=r;++i) {
		int pos=std::lower_bound(dp,dp+x+1,q[i])-dp;
		if(pos==x+1) return false;
		x-=pos;
	}
	return true;
}*/

bool check(int x) {
	for(int i=x;i<=n;++i) {
		/*if(sum[i]-sum[i-x]<=dp[k]) {
			if(count(i-x+1,i)) f=1;
			if(f) break;
		}*/
		if(coast[i]-coast[i-x]<=k) return true;
	}
	return false;
}

int main() {
	//freopen("attack.in","r",stdin);
	//freopen("attack.out","w",stdout);
	read(m),read(n),read(k);
	for(int i=1;i<=m;++i) read(zz[i].c);
	for(int i=1;i<=m;++i) read(zz[i].a);
	for(int i=1;i<=n;++i) {
		read(q[i]);
		sum[i]=sum[i-1]+q[i];
	}
	for(int i=1;i<=m;++i) {
    	for(int l=zz[i].c;l<=k;++l) {
      		if(dp[l-zz[i].c]+zz[i].a>dp[l]) dp[l]=dp[l-zz[i].c]+zz[i].a;
      	}
	}
	for(int i=1;i<=n;++i) {
		coast[i]=coast[i-1]+(std::lower_bound(dp,dp+k+1,q[i])-dp);
	}
	int l=1,r=n,ans=0;
	while(l<=r) {
	    int mid=(l+r)>>1;
	 	if(mid==0) break;
	 	if(check(mid)) l=mid+1,ans=mid;
	 	else r=mid-1;
	}
	std::cout<<ans<<'\n';
	fclose(stdin),fclose(stdout);
	return 0;
}

反思:

  • 太菜了。
posted @ 2020-06-14 21:49  yu__xuan  阅读(108)  评论(0编辑  收藏  举报