DLUT《大工之星》编程挑战赛12.17日赛后题解

PS:今天是挑战赛的最后一场,是不是感觉今天的题不难呢~~~

现在开始正题:

T1:妈妈生日快乐!

        签到

T2: 提瓦特大陆交通线

        本题考查并查集的应用;

在此为大家讲解一下并查集:

                个人感觉这篇文章写的比较好,不懂的可以看看(转自博客园Ark)https://www.cnblogs.com/Orz-IE/p/12039536.htmlicon-default.png?t=N7T8https://www.cnblogs.com/Orz-IE/p/12039536.html            先上代码:

    

#include <bits/stdc++.h>
using namespace std;
int fa[1000001], n, m, x, y;
int find(int x)//并查集(路径压缩)
{
    if(x != fa[x])//当x不等于它的爸爸时(当它是祖先时,它没有爸爸)
    {
        fa[x] = find(fa[x]);//继续找他的爸爸的爸爸
    }
    return fa[x];//返回祖先
}//查找
void unity(int x, int y)
{
    int r1 = find(x);//找到x的祖先
    int r2 = find(y);//找到y的祖先
    fa[r1] = r2;//祖先和祖先结为父子(谁是父亲谁是儿子都可以)
}//合并
int main()
{
		int ans = 0;//ans要在循环中定义为0
		scanf("%d", &n);
		if(n == 0)
		{
			return 0;
		}
		scanf("%d", &m);
	    for(int i = 1; i <= n; i++)
	    {
	        fa[i] = i;//初始化自己的父亲是自己
	    }
	    for(int i = 1; i <= m; i++)
	    {
	        scanf("%d %d", &x, &y);
	        unity(x, y);//合并x和y
	    }
	    for(int i = 1; i <= n; i++)
	    {
	    	if(find(i) == i)//自己的父亲等于自己本身
	    	{
	    		ans++;
			}
		}
		printf("%d\n", ans - 1);//答案减一
    return 0;
}

本题只需使用并查集,每次插入边的时候做一次路径压缩和父节点的合并,最后得到的fa数组里面元素的种类个数就是整个森林中树的数目ans。为了让它们连接成一个道路网,就需要ans-1条边来连接(这个不用证了吧)

在此推荐一个题:[NOIP2017 提高组] 奶酪 - 洛谷

完结撒花...

T7:lzq要开始学习了

本题核心算法为贪心

求一个学习顺序使得学习总用时最短,就是让空闲时间最短。。

可以大胆猜想,要使车间的空闲时间最短,就要把在A车间上加工时间最短的产品最先加工,这样使得B车间能在最短的空闲时间内开始加工

所以我们应该让在A车间上加工时间短的产品优先,而在B车架上加工时间短的产品排在后面

所以我们要做的事就要把在预习时间最短的优先,这样能以最快的速度开始复习

类似算法又叫Johnson算法,就是变成可以同时预习和复习,感兴趣的同学可以去了解一下。

H:神奇的数学

这道题直接推到一个递推公式不是很容易但是可以一个一个拆分
例如样例7;从大到小向外拆分2的幂
找到比7小的最大的2的幂是4,
如果拆出4,可以继续往后统计3的拆分但不会拆出比4大的数的个数(3=2+1=1+1+1)
如果拆出2,可以继续往后统计5拆分但是不比2大的数的个数(5=2+2+1=2+1+1+1=1+1+1+1+1)
如果拆出1,可以继续往后统计6拆分但是不比1大的数的个数(6=1+1+1+1+1+1)
而后我们发现不比2的n次幂大的数这个限制可以用背包来解决,将2的n次幂放到外面当做背包dp的物品循环,而且拆分结果会出现若干同样数的情况,所以是完全背包dp,接下来看代码实现(很简单的)

#include<bits/stdc++.h>
using namespace std;
long long sum[100],dp[1000001];
int n,ans,mod=1e9+7;
 
void chuli(){
	int p=1;
	while(p<=n){
		sum[ans++]=p;
		p=p<<1;
	}
}
 
int main(){
	cin>>n;
	chuli();
	dp[0]=1;
	for(int i=0;i<ans;i++){
		for(int j=sum[i];j<=n;j++){
			dp[j]=(dp[j]+dp[j-sum[i]])%mod;
		}
	}
	cout<<dp[n];
	return 0;
}

剩余部分题解详见https://blog.csdn.net/weixin_46494925/article/details/135034426

(今天满课,题解出晚了,见谅哦~)

  • 18
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值