夏令营501-511NOIP训练18

本文解析了三道算法竞赛题目,包括高一学堂的微博转发问题,高二学堂的加强版扑克牌组合问题,以及高三楼的矩阵组合问题。通过深入分析,提供了具体的解题思路和代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

T1 高一学堂

高一学堂,因为有了yxryxryxr,就成了现在这个样子 = =。由于yxryxryxr 的语言太过雷人,每次他发微往往都会有一石激起千层浪的效果,具体就是所有关注他的人都会转发,同时@@@他,接着关注这些人的人也会转发,同时@@@他关注的人(注意转发内容本身会有@@@yxryxryxr),以此类推。这样导致每次yxryxryxr 发微博都会被@@@上兆次,而yxryxryxr 又特别喜欢发,sina 支持不了如此庞大的数据量,特出规定,每次转发时,@@@的人不能超过K 人,好友在转发时如果超过了,就把最早那人删掉。现在yxryxryxr 刚发了一条微博“求满分”,他想知道每个与他有联系的人分别会被@@@多少次。


输入格式:

输入第一行有三个整数,NNNKKK,表示人数和KKK
接下来 N−1N-1N1 行,每行有2 个整数 aaabbb,表示 aaabbb 有关注关系。
输入给出一棵以 111 号点为根的树,一号点代表 yxryxryxr,对于任意一个点,他的儿子都关注他。

输出格式:

输出有 NNN 行,每行有一个整数,这个人会被 @@@ 多少次。


样例输入:
5 2
1 2
2 3
2 4
4 5
样例输出:
3
3
0
1
0

数据范围:
对于30%30\%30%的数据,NNN ≤100;
对于60%60\%60%的数据,NNN ≤2000,KKK ≤100;
对于100%100\%100%的数据,NNN ≤100000, KKKNNN


题解:
  • 其实就是求每个结点深度差不超过 KKK 的儿子个数
  • 每个结点的儿子个数 - 它 k+1k+1k+1 层每个儿子的儿子个数
#include <bits/stdc++.h>
using namespace std;
vector<int> a[100010];
vector<int> b[100010];
int d[100010],h[100010],k;
void dfs(int u,int fa,int dep)
{
	d[u]=dep;
	for(int i=0; i<a[u].size(); i++)
	{
		int v=a[u][i];
		if(v==fa) continue;
		dfs(v,u,dep+1);
		h[u]+=h[v]+1;
	}
}
void dfs_2(int u,int fa,int dep)
{
	b[d[u]].push_back(u); // 当前子树下,此深度的结点
	if(b[dep-k-1].size()&&dep-k-1>0)  // 减掉它k+1儿子结点的儿子个数
	{
		for(int i=0; i<b[dep-k-1].size(); i++)
		{
			int v=b[dep-1-k][i];
			h[v]=h[v]-h[u]-1;
		}
	}
	for(int i=0; i<a[u].size(); i++)
	{
		int v=a[u][i];
		if(v==fa) continue;
		dfs_2(v,u,dep+1);
	}
	// 回溯时把当前结点删除
	vector<int>::iterator it;
	for(it=b[d[u]].begin();it!=b[d[u]].end();it++)
		if(*it==u)
		{
			b[d[u]].erase(it);
			break;
		}
}
int main()
{
	int n,i,x,y;
	scanf("%d%d",&n,&k);
	for(i=1; i<n; i++)
	{
		int x,y;
		scanf("%d%d",&x,&y);
		a[x].push_back(y);
		a[y].push_back(x);
	}
	dfs(1,0,1);    //  记录深度和儿子结点的个数
	dfs_2(1,0,1);
	for(i=1; i<=n; i++) printf("%d\n",h[i]);
	return 0;
}

T2 高二学堂

Wayne 有一副加强版的扑克牌,强大到任意取一个自然数x,在牌堆里都恰
444 张数值为 xxx 的牌。每次,Wayne 随机生成两个正整数 nnn 和k,然后在牌堆里选取不超过 kkk 张牌,使得牌面数字之和恰为 nnn。已知Wayne 玩了若干盘,每盘都算出了对应的方案数,他想请你也算出各盘方案数,以验算他的结果是否正确。结果可能比较大,你只需要求出方案数modmodmod 1000000009(1e9+9) 的值即可。


输入格式:

输入文件包含不超过101010 组数据。
每行包含两个整数,表示上文中的 nnnkkk
输入数据以两个000 表示结束。

输出格式:

输出文件中,每组数据输出一行,为对应的方案数。


样例输入:
2 1
2 2
2 3
50 5
0 0
样例输出:
4
10
10
1823966

数据范围:
对于 10%10\%10%的数据,kkk=1;
对于 20%20\%20%的数据,nnn ≤10,kkk ≤4;
对于 40%40\%40%的数据,nnn ≤1000;
对于 60%60\%60%的数据,nnn ≤100000;
对于另外 20%20\%20% 的数据,只有 111 组数据;
对于 100%100\%100%的数据,nnn ≤10^9,kkk ≤10。


题解
  • 不好意思目前本蒟蒻只会404040分做法,等以后会100100100分了再回来更新(也许你等不到这一天)
  • (题意)选取不超过 kkk 个数,每个数可以取至多444个,不考虑000,使得数字之和为 nnn
  • dp[i][j]dp[ i ][ j ]dp[i][j] : 和为 iii ,取 jjj 个数的方案数
#include <bits/stdc++.h>
using namespace std;
const int mod=1e9+7;
long long d[100010][12],c[10][10];
int main()
{
	int n,k,i,j,l;
	memset(d,0,sizeof(d));
	c[4][1]=c[4][3]=4;
	c[4][2]=6;
	c[4][4]=1;
	d[0][0]=1;
	for(i=1; i<=1000; i++)  //  当前正在取 i 
		for(j=10;j>=1;j--)  // 取 j 个数
			for(l=0; l<=1000; l++) // 和为 l
				for(k=1; k<=min(4,j)&&k*i+l<=1000; k++)  // i 取 k 个
					d[k*i+l][j]=(d[k*i+l][j]+(d[l][j-k]*c[4][k])%mod)%mod;
		
	while(scanf("%d%d",&n,&k)!=EOF)
	{
		if(!n&&!k) break;
		long long s=0;
		for(i=1; i<=k; i++) s=(s+d[n][i])%mod;
		printf("%lld\n",s);
	}
	return 0;
}

T3 高三楼

一个 n∗nn * nnn 的矩阵,其中,每行每列都有两个特殊的点。
"重复"的定义为矩阵 aaa ,通过任意次行列变换,变成了矩阵 bbb,矩阵 aaabbb就视为重复。
例如:对于 3∗33*333 的矩阵,其中矩阵 aaa 与矩阵 bbb 被视为“重复”矩阵。
在这里插入图片描述
对于一个 nnn,可以有多少种不“重复”的矩阵,输出答案modmodmod100000007(1e8+7) 的值。


输入格式:

第一行,一个整数 ttt,表示数据组数。
接下来 ttt 行,每行一个整数 nnn,表示一组数据。

输出格式:

TTT 行,每行一个整数,表示方案数。由于答案可能很大,只需要输出方案数
mod100,000,007mod 100,000,007mod100,000,007 的值就可以了。


样例输入:
3
2
3
4
样例输出:
1
1
2

数据范围:
对于10%10\%10%的数据 NNN555
对于50%50\%50%的数据 NNN150150150
对于100%100\%100%的数据 TTT555NNN200020002000


题解
  • 此题解法神奇,因为每行每列只有两个标记,所以我们可以把,想成一个二分图的两条边
  • 两条边之间的连线等价于某一个标记
  • 两条边上的点的移动等价于标记的行列变换
  • 所以我们只要考虑有多少种不同的连法即可
  • e.g. (可以手模以下 n=5n = 5n=5
    n = 4
    • 然后——惊奇地发现(๑╹◡╹)ノ(๑╹◡╹)ノ()2∗x(1&lt;x&lt;=n)2*x(1 &lt; x &lt;= n)2x1<x<=n点就会构成一个环
    • 每种环的组成,代表一种方案,排列并不重要
    • So—— n=a1+a2+......+amn = a_1+a_2+......+a_mn=a1+a2+......+am (am&gt;1)(a_m &gt; 1)(am>1)
    • 于是就转化成了正整数拆分的问题︿( ̄︶ ̄)︿︿( ̄︶ ̄)︿︿()︿
#include <bits/stdc++.h>
using namespace std;
const int mod=1e8+7;
int d[100010];
int main()
{
	int i,j;
	memset(d,0,sizeof(d));
	d[0]=1;
	for(i=2;i<=2000;i++)
		for(j=i;j<=2000;j++) d[j]=(d[j]+d[j-i])%mod;
	//  j = i + ( j - i )
	scanf("%d",&i);
	while(i--)
	{
		scanf("%d",&j);
		printf("%d\n",d[j]);
	}
	return 0;
}
内容概要:该研究通过在黑龙江省某示范村进行24小时实地测试,比较了燃煤炉具与自动/手动进料生物质炉具的污染物排放特征。结果显示,生物质炉具相比燃煤炉具显著降低了PM2.5、CO和SO2的排放(自动进料分别降低41.2%、54.3%、40.0%;手动进料降低35.3%、22.1%、20.0%),但NOx排放未降低甚至有所增加。研究还发现,经济性和便利性是影响生物质炉具推广的重要因素。该研究不仅提供了实际排放数据支持,还通过Python代码详细复现了排放特征比较、减排效果计算和结果可视化,进一步探讨了燃料性质、动态排放特征、碳平衡计算以及政策建议。 适合人群:从事环境科学研究的学者、政府环保部门工作人员、能源政策制定者、关注农村能源转型的社会人士。 使用场景及目标:①评估生物质炉具在农村地区的推广潜力;②为政策制定者提供科学依据,优化补贴政策;③帮助研究人员深入了解生物质炉具的排放特征和技术改进方向;④为企业研发更高效的生物质炉具提供参考。 其他说明:该研究通过大量数据分析和模拟,揭示了生物质炉具在实际应用中的优点和挑战,特别是NOx排放增加的问题。研究还提出了多项具体的技术改进方向和政策建议,如优化进料方式、提高热效率、建设本地颗粒厂等,为生物质炉具的广泛推广提供了可行路径。此外,研究还开发了一个智能政策建议生成系统,可以根据不同地区的特征定制化生成政策建议,为农村能源转型提供了有力支持。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值