2023.3.7拷逝题解

T1 草种子(dendro)

由题目可知,每一列最多有两个草种子,每一行最多有两个草种子。

设当前要在 nm(n>=m) 上填充草种子,我们在第一行和第二行的第一列上填充两个草种子。这样,第一行,第二行,第一列就再也不能填充其他种子了,问题规模就缩减到了(n2,m1),然后递归求解即可。

递归边界:

n=m=1 时,ans=1;

n=1,m=2 时,ans=2;

n=2,m=1 时,ans=2;

n=m=2 时,ans=2.

code:

#include<iostream>
#include<cstdio>
using namespace std;
long long t,n,m;
long long dfs(long long a,long long b){
	if(a==1&&b==1)
		return 1;
	else if(a==1&&b==2)
		return 2;
	else if(a==2&&b==1)
		return 2;
	else if(a==2&&b==2)
		return 2;
	if(a<b)
		swap(a,b);
	long long d=a-b;
	if(a>=b*2)
		return b*2;
	if(d>0)
		return dfs(a-d*2,b-d)+d*2;
	if(d==0)
		return dfs(a%3,b%3)+a/3*4;
}
int main(){
	//freopen("dendro.in","r",stdin);
	//freopen("dendro.out","w",stdout);
	scanf("%lld",&t);
	while(t--){
		scanf("%lld%lld",&n,&m);
		if(n<m)
			swap(n,m);
		printf("%lld\n",dfs(n,m));
	}
	fclose(stdin);fclose(stdout);
	return 0;
}

T2 数列(seq)

不难发现这道题需要搜索,但是如果是正常的搜索会超时,所以我们需要双向搜索。具体细节见代码。

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
long long n,a[15],s,rsum[15],ans,f[15][50],cnt,sum[2000005],n1;
bool cmp(long long x,long long y){
	return x>y;
}
long long fast_mul(long long x,long long y){
	long long sum=x;x=1;
	while(y){
		if(y&1){
			x*=sum;
			if(x>1e9)
				return 2e9;
		}
		sum*=sum;
		y>>=1;
		if(sum>1e9&&y)
			return 2e9;
	}
	return x;
}
void dfs1(long long x,long long y){
	if(y>s)
		return ;
	if(x==n1+1&&y<=s){
		sum[++cnt]=y;
		return ;
	}
	for(int i=1;y+f[x][i]<=s;++i)
		dfs1(x+1,y+f[x][i]);
}
void dfs2(long long x,long long y){
	if(y>s)
		return ;
	if(x==n+1&&y<=s){
		long long pos=upper_bound(sum+1,sum+cnt+1,s-y)-sum;
		while(pos>cnt||sum[pos]+y>s)
			--pos;
		ans+=pos;
		return ;
	}
	for(int i=1;y+f[x][i]<=s;++i)
		dfs2(x+1,y+f[x][i]);
}
int main(){
	//freopen("seq.in","r",stdin);
	//freopen("seq.out","w",stdout);
	scanf("%lld%lld",&n,&s);
	for(int i=1;i<=n;++i)
		scanf("%lld",&a[i]);
	sort(a+1,a+n+1,cmp);
	for(int i=1;i<=n;++i)
		for(int j=1;j<=35;++j)
			f[i][j]=fast_mul(a[i],j);
	n1=(1+n)>>1;
	dfs1(1,0);
	sort(sum+1,sum+cnt+1);
	dfs2(n1+1,0);
	printf("%lld\n",ans);
	fclose(stdin);fclose(stdout);
	return 0;
}

T3 虚空终端(terminal)

我们将生论派看作 0 号节点,名论派看作 n+1 号节点。容易发现答案只有四种情况:

只有1~n号节点的最小生成树;

只有0~n号节点的最小生成树;

只有1~n+1号节点的最小生成树;

0~n+1号节点的最小生成树

分别按照上述四种情况连边,然后跑四次最小生成树,答案就是四次最小生成树的最小值。

code:

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
long long n,m,tot,x[500005],y[500005],a[500005],b[500005],z[500005],fa[500005],ans,sum,cnt;
struct node{
	long long u,v,w;
} e[1000005];
bool cmp(node a,node b){
	return a.w<b.w;
}
long long _find(long long x){
	if(fa[x]==x)
		return x;
	return fa[x]=_find(fa[x]);
}
void f(long long edge){
	sort(e+1,e+tot+1,cmp);
	for(int i=0;i<=n+1;++i)
		fa[i]=i;
	sum=cnt=0;
	for(int i=1;i<=tot;++i){
		long long a=_find(e[i].u),b=_find(e[i].v);
		if(a!=b){
			fa[a]=b;++cnt;sum+=e[i].w;
		}
		if(cnt>=edge)
			break;
	}
	if(cnt==edge)
		ans=min(ans,sum);
}
int main(){
	//freopen("terminal.in","r",stdin);
	//freopen("terminal.out","w",stdout);
	scanf("%lld%lld",&n,&m);
	ans=1e18;
	for(int i=1;i<=n;++i)
		scanf("%lld",&x[i]);
	for(int i=1;i<=n;++i)
		scanf("%lld",&y[i]);
	for(int i=1;i<=m;++i){
		scanf("%lld%lld%lld",&a[i],&b[i],&z[i]);
		e[++tot].u=a[i],e[tot].v=b[i],e[tot].w=z[i];
	}
	f(n-1);
	tot=0;
	for(int i=1;i<=m;++i)
		e[++tot].u=a[i],e[tot].v=b[i],e[tot].w=z[i];
	for(int i=1;i<=n;++i)
		e[++tot].u=0,e[tot].v=i,e[tot].w=x[i];
	f(n);
	tot=0;
	for(int i=1;i<=m;++i)
		e[++tot].u=a[i],e[tot].v=b[i],e[tot].w=z[i];
	for(int i=1;i<=n;++i)
		e[++tot].u=n+1,e[tot].v=i,e[tot].w=y[i];
	f(n);
	tot=0;
	for(int i=1;i<=m;++i)
		e[++tot].u=a[i],e[tot].v=b[i],e[tot].w=z[i];
	for(int i=1;i<=n;++i){
		e[++tot].u=0,e[tot].v=i,e[tot].w=x[i];
		e[++tot].u=n+1,e[tot].v=i,e[tot].w=y[i];
	}
	f(n+1);
	printf("%lld\n",ans);
	fclose(stdin);fclose(stdout);
	return 0;
}
posted @   andy_lz  阅读(15)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
点击右上角即可分享
微信分享提示