2022中国大学生程序设计竞赛(CCPC)高职专场

news2024/11/25 10:50:24

一,期望

题意:

  • 初始时你有1−n这n个正整数和一个空的序列,你准备玩一个往序列中加数字的无聊游戏。
  • 游戏进行n轮,在游戏的每一轮中你要向序列尾部加入一个还未被加入的数,最终的序列将会是一个长度为n的排列。
  • 在某一轮游戏开始前,令此时所有未被加入的数的和是sum,那么这一轮加入一个未被加入的数x的概率是sumx​。
  • 求最终序列逆序对个数的期望,答案对109+7取模。
  • 对于一个序列a1​,a2​,...,an​,对于(i,j)满足,ai​>aj​且1≤i<j≤n,则称(ai​,aj​)是一对逆序对。

思路:

  1. 考虑一对逆序对(i,j)在所有排列下出现的期望。发现显然i出现在j前面,与其他数无关,所以所有排列下i出现在j前面的期望都是\frac{i}{j+i}(i>j)
  2. 所以答案就是所有逆序对的期望相加。观察出相加实际就是等差数组求和
#include <bits/stdc++.h>
using namespace std;
#define ll               long long
#define endl             "\n"
#define int              long long
const int N = 3e5 + 10;
const int mod=1e9+7;

ll fastmi(ll base, ll power)
{
	ll ans = 1;
	while (power)
		{
			if (power & 1)ans=ans*base%mod;
			base=base*base%mod;
			power >>=1;
		}
	return ans;
}

void mysolve()
{
	int n;
	cin>>n;
	int ans=0;
	for(int i=3; i<=2*n-1; ++i)
		ans=(ans+((min(i-1,n)+i/2+1)*(min(i-1,n)-i/2)/2)%mod*fastmi(i,mod-2)%mod)%mod;
	cout<<ans<<endl;
}

int32_t main()
{
	std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
	ll t=1;
	//cin >> t;
	while (t--)
		{
			mysolve();
		}
	system("pause");
	return 0;
}

重排数组

题意

  • 给定一个长度为n的数组a1​,a2​,...,an​,定义一个数组的权值为将数按照下标顺序拼接在一起
  • 例如:一个长度为3的数组a1​=11,a2​=12,a3​=2,那么数组的权值为11122
  • 现在要求出数组a的所有排列的权值和,答案对109+7取模
  • 对于长度为n的数组有n!种排列,例如对于a1​,a2​,a3​来说,有6种排列分别是:a1​,a2​,a3​ ; a1​,a3​,a2​ ; a2​,a1​,a3​ ; a2​,a3​,a1​ ; a3​,a1​,a2​ ; a3​,a2​,a1​.

思路:

  1. ai在每个排列的贡献,取决有前面的有多少个元素
  2. 设dp[i][j]为前i个元素,处理了j个在前面产生的贡献,如果我们求出来dp[i][j]。显然ai前面有k个元素时,他的贡献就是A[k]*ai*dp[i][k]*A[n-1-k](A[]为排列数)
  3. 怎么算dp的贡献呢,显然每个元素的贡献取决有他有多少位,设元素p有b位,显然有转移方程式dp[i][j+1]=dp[i][j]*10^{b}(无论他插在j个元素里的哪个位置,显然都是使dp[i][j]的贡献在10进制上左移了b位(即*10^b)
  4. 因为每个数讨论前面的数的情况是不能有他自己的,显然我们每个元素都要自己做一次dp,用背包优化可以设当降低复杂度
#include <bits/stdc++.h>
using namespace std;
#define ll               long long
#define endl             "\n"
#define int              long long
typedef pair<int, int> pii;
const int N = 2000+20;

int mycnt(int x)
{
	int ans=0;
	while(x)ans++,x/=10;
	return ans;
}
const int mod=1e9+7;
pii a[N];
int pre[N],A[N];//pre表示10的几次幂,A是排列数
void mysolve()
{
	int n;
	cin>>n;
	for(int i=1; i<=n; ++i)cin>>a[i].first,a[i].second=mycnt(a[i].first);
	int ans=0;
	for(int i=1; i<=n; ++i)
		{
			vector<int>dp(n+1);//讨论当前元素a[i]在所有排列的总贡献,先给他处理下dp
			dp[0]=1;
			for(int j=1,p=0; j<=n; ++j)if(i!=j)//背包优化
					{
						p++;//p表示处理了p个数
						for(int k=p; k; --k)dp[k]=(dp[k]+dp[k-1]*pre[a[j].second]%mod)%mod;
					}
			for(int j=0; j<n; ++j)//枚举ai前面有几个元素的情况时的贡献
				ans=(ans+a[i].first*A[n-j-1]%mod*dp[j]%mod*A[j]%mod)%mod;
		}
	cout<<ans<<endl;
}

int32_t main()
{
	std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
	pre[0]=1,A[0]=1;
	for(int i=1; i<=2000; ++i)pre[i]=pre[i-1]*10%mod,A[i]=A[i-1]*i%mod;
	mysolve();
	system("pause");
	return 0;
}

寻宝

题意

  • 探险队获得了一张藏宝图,藏宝图中有n个洞穴,还有n−1条道路连通这n个洞穴,对于任意两个不同的洞穴,都可以通过道路相互到达。
  • 在藏宝图中,一些洞穴里被标记有宝藏。
  • 探险队决定选取一些有宝物的洞穴作为寻宝计划,他们会从寻宝计划中的一个洞穴出发,依次到达每个寻宝计划中其他的洞穴收集宝物,最后再回到出发的洞穴,在这个过程中,他们会选择路程最少的寻宝路线。可以证明,无论从寻宝计划中的哪个洞穴出发,最终的最小路程都是相同的。
  • 一次探险的路程是探险中经过的道路数量。
  • 现在你需要计算对于每个k(1≤k≤n),在探险队任选k个有宝物的洞穴作为寻宝计划时,他们要走的最小路程最多是多少,最少是多少?

思路:

  1. 树上dp,以最大值为例,dp[u][k]维护好处理到子树u,k个宝藏的最长距离。
  2. 而答案就是每次子树给入父节点时更新答案
#include <bits/stdc++.h>
using namespace std;
#define ll               long long
#define endl             "\n"
const int INF = 0x3f3f3f3f;         //int型的INF
const double eps=1e-9;
const int N = 3e3 + 10;

vector<int>edge[N];
int mxans[N],mnans[N],mxdp[N][N],mndp[N][N],sz[N];
bool a[N];
int n;
void dfs(int u,int f)
{
	sz[u]=1;
	for(auto v:edge[u])if(v!=f)
			{
				dfs(v,u);
				for(int i=sz[u]; ~i; --i)for(int j=sz[v]; j; --j)
						{
							mxdp[u][i+j]=max(mxdp[u][i+j],mxdp[u][i]+mxdp[v][j]+2);
							mndp[u][i+j]=min(mndp[u][i+j],mndp[u][i]+mndp[v][j]+2);
							if(i)
								{
									mxans[i+j]=max(mxans[i+j],mxdp[u][i]+mxdp[v][j]+2);//这里不写mxdp[u][i+j],因为u的i+j是可以由i=0,j>0更新得到,但是子树合并必须ij均大于0合并,才算是最短路径的最大值,否者不符合最短路径的定义
									mnans[i+j]=min(mnans[i+j],mndp[u][i]+mndp[v][j]+2);
								}
						}
				sz[u]+=sz[v];
			}
}
void mysolve()
{

	cin>>n;
	for(int i=1; i<=n; ++i)
		{
			mxans[i]=-INF;
			mnans[i]=INF;
			for(int j=1; j<=n; ++j)mxdp[i][j]=-INF,mndp[i][j]=INF;
		}
	for(int i=1; i<=n; ++i)
		{
			cin>>a[i];
			if(a[i])mxdp[i][1]=mndp[i][1]=0,mxans[1]=mnans[1]=0;
		}
	int x,y;
	for(int i=1; i<n; ++i)cin>>x>>y,edge[x].push_back(y),edge[y].push_back(x);
	dfs(1,0);
	for(int i=1; i<=n; ++i)
		{
			if(mxans[i]>=0)cout<<mxans[i]<<" "<<mnans[i]<<endl;
			else
				cout<<-1<<" "<<-1<<endl;
		}
}

int32_t main()
{
	std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
	ll t=1;
	//cin >> t;
	while (t--)
		{
			mysolve();
		}
	system("pause");
	return 0;
}

数三角形

题意:

  • 作为一名学霸,当然要学会数数,不仅要会数正方体,也要会数三角形。
  • 在二维平面上存在位置互不相同的n个点,这些点的横纵坐标均为整数,第i个点的坐标为(ai​,bi​)。你需要计算存在多少个三元组(i,j,k)(1≤i<j<k≤n)满足i,j,k三个点可以构成面积大于0的等腰三角形。
  • 当然了,为了简化一些计算量,本题还满足一个特殊性质:这n个点仅存在于两条距离不超过10的平行于x轴的直线上。

思路:

  1. 首先清楚三角形有2种,一种有一条腰在线上,一种是两条腰都不在线上。显然这两种不冲突(因为格点上不存在等边三角形)
  2. 第一种情况,如果腰只有一条不在线上,那么首先他是完全平方数,而可以匹配的完全平方数的对数是很少的,这个可以暴力枚举
  3. 对于第二种情况,需要枚举i+j=2*k,暴力是O(n),发现ai<=1e5,那么用NNT实现nlogn求寻i+j的各种组合数
#include <bits/stdc++.h>
using namespace std;
#define ll               long long
#define int              long long
typedef pair<int, int> pii;
const int N = 3e5 + 10,G = 3, Gi = 332748118;
const int mod=998244353;

vector<pii>pre[15];
int limit,L;
int r[N];
void init()
{
	pre[3].push_back({4,5+4});
	pre[4].push_back({3,5+3});
	pre[5].push_back({12,13+12});
	pre[6].push_back({8,10+8});
	pre[7].push_back({24,25+24});
	pre[8].push_back({6,10+6});
	pre[8].push_back({15,17+15});
	pre[9].push_back({12,15+12});
	pre[9].push_back({40,41+40});
	pre[10].push_back({24,26+24});
}

ll fastmi(ll base, ll power)
{
	ll ans = 1;
	while (power)
		{
			if (power & 1)ans=ans*base%mod;
			base=base*base%mod;
			power >>=1;
		}
	return ans;
}

inline void NTT(ll *A, int type)
{
	for(int i = 0; i < limit; i++)
		if(i < r[i]) swap(A[i], A[r[i]]);
	for(int mid = 1; mid < limit; mid <<= 1)
		{
			ll Wn = fastmi( type == 1 ? G : Gi, (mod - 1) / (mid << 1));
			for(int j = 0; j < limit; j += (mid << 1))
				{
					ll w = 1;
					for(int k = 0; k < mid; k++, w = (w * Wn) % mod)
						{
							int x = A[j + k], y = w * A[j + k + mid] % mod;
							A[j + k] = (x + y) % mod,
							           A[j + k + mid] = (x - y + mod) % mod;
						}
				}
		}
}

ll aa[N],bb[N];
void mysolve()
{
	vector<int>a1,b1;
	unordered_map<int,int>a,b;
	int n,A,B;
	cin>>n>>A>>B;
	int x1,y1;
	for(int i=1; i<=n; ++i)
		{
			cin>>x1>>y1;
			if(y1==A)a[x1]=1,a1.push_back(x1);
			else b[x1]=1,b1.push_back(x1);
		}
	int ans=0;
	int d=abs(A-B);
	sort(a1.begin(),a1.end()),sort(b1.begin(),b1.end());

	for(auto v:a1)//暴力枚举第一种
		{
			for(pii u:pre[d])
				{
					if(b.count(v+u.first)&&b.count(v+u.second))ans++;
					if(b.count(v-u.first)&&b.count(v-u.second))ans++;
					if(b.count(v+u.first)&&b.count(v-(u.second-2*u.first)))ans++;
					if(b.count(v-u.first)&&b.count(v+(u.second-2*u.first)))ans++;
				}
			if(b.count(v+d)&&b.count(v))ans++;
			if(b.count(v-d)&&b.count(v))ans++;
			ans%=mod;
		}
	for(auto v:b1)
		{
			for(pii u:pre[d])
				{
					if(a.count(v+u.first)&&a.count(v+u.second))ans++;
					if(a.count(v-u.first)&&a.count(v-u.second))ans++;
					if(a.count(v+u.first)&&a.count(v-(u.second-2*u.first)))ans++;
					if(a.count(v-u.first)&&a.count(v+(u.second-2*u.first)))ans++;
				}
			if(a.count(v+d)&&a.count(v))ans++;
			if(a.count(v-d)&&a.count(v))ans++;
			ans%=mod;
		}

	limit=1,L=0;//NNT计算i+j枚举后各个数的出现次数
	while(limit<=2e5)limit<<=1,L++;
	for(int i = 0; i < limit; i++)
		r[i] = (r[i >> 1] >> 1) | ((i & 1) << (L - 1));
	for(int i=0; i<=1e5; ++i)
		{
			if(a[i])aa[i]=1;
			if(b[i])bb[i]=1;
		}
	NTT(aa,1),NTT(bb,1);
	for(int i=0; i<limit; ++i)aa[i]=aa[i]*aa[i]%mod,bb[i]=bb[i]*bb[i]%mod;//多项式a*a
	NTT(aa,-1),NTT(bb,-1);
	ll inv=fastmi(limit,mod-2);
	for(int i=0; i<=2e5; ++i)aa[i]=aa[i]*inv%mod,bb[i]=bb[i]*inv%mod;

	int res=0;
	for(int i=0; i<=1e5; ++i)
		{
			if(a[i])res+=bb[i<<1]-b[i];//减去i+i的情况
			if(b[i])res+=aa[i<<1]-a[i];
		}
	ans=(ans+res/2)%mod;//因为i+j与j+i各自算了一次,要除2
	cout<<ans<<endl;
}

int32_t main()
{
	std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
	ll t=1;
	//cin >> t;
	while (t--)
		{
			init();
			mysolve();
		}
	system("pause");
	return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/574566.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

五、Docker仓库之https的registry搭建(二)

本节我们分享更多的实用的仓库搭建使用方式。包括支持https的registry、Harbor、nexus。 支持HTTPS的registry 准备站点证书&#xff08;测试使用&#xff0c;用一个自己的测试域名&#xff0c;配置本地hosts&#xff09; 如果你拥有一个公网域名&#xff0c;那很好&#xff…

ESP-01模块刷固件

ESP-01模块刷固件 0.前言一、准备二、烧写1.接线2.软件设置3.检验 0.前言 最近需要用esp-01模块作为wifi模块上云&#xff0c;但由于出厂自带固件太过老旧&#xff0c;经常会出现奇奇怪怪的警告&#xff0c;所以记录下如何给ESP-01刷写较新的固件。 一、准备 需要准备三个东西…

Python之并发编程一背景知识

一、开篇介绍 顾名思义&#xff0c;进程即正在执行的一个过程。进程是对正在运行程序的一个抽象。 进程的概念起源于操作系统&#xff0c;是操作系统最核心的概念&#xff0c;也是操作系统提供的最古老也是最重要的抽象概念之一。操作系统的其他所有内容都是围绕进程的概念展…

大型软件外包开发管理工具

大型软件项目涉及人员多&#xff0c;软件代码量大&#xff0c;业务复杂&#xff0c;因此需要借助软件工程的管理工具进行管理&#xff0c;否则容易隐入混乱。今天和大家分享这些工具&#xff0c;这些工具比较实用&#xff0c;在实际工作中使用广泛&#xff0c;希望对大家有所帮…

Linux常规基础配置

通过VMware成功安装RHEL7服务器后&#xff0c;为了能够正常使用&#xff0c;需要对其进行常规的一些基础配置&#xff0c;主要有&#xff1a;关闭防火墙与selinux&#xff0c;设置主机名&#xff0c;配置虚拟机IP地址使其能够与外网ping通&#xff0c;配置IP地址与主机名映射&a…

从小白到大神之路之学习运维第29天

第二阶段基础 时 间&#xff1a;2023年5月25日 参加人&#xff1a;全班人员 内 容&#xff1a; Apache服务 目录 一、基本信息 二、安装方法 三、配置方法 四、虚拟主机头 1&#xff1a;基于不同的IP地址 2&#xff1a;基于不同的端口 3&#xff1a;基于不同的域…

SQL 教程(2)

SQL 函数 SQL 拥有很多可用于计数和计算的内建函数。 SQL Aggregate 函数 SQL Aggregate 函数计算从列中取得的值&#xff0c;返回一个单一的值。 有用的 Aggregate 函数&#xff1a; AVG() - 返回平均值COUNT() - 返回行数FIRST() - 返回第一个记录的值LAST() - 返回最后…

C++回调函数理解

C回调函数理解 0.引言1.回调函数的实现方式2.普通函数以函数指针的形式进行实现3.类成员函数以静态函数进行实现4.类成员函数以非静态函数进行实现5.std::funtion和std::bind的使用6.c回调的实现7.应用实例 0.引言 看了一些介绍感觉太官方了&#xff0c;我的简单理解就是从模式…

3D点云深度学习处理的基本概念

权重矩阵更新学习方法概述 参数初始化&#xff1a; 需要对权重矩阵初始化参数&#xff08;通常使用随机初始化方法&#xff0c;如正态分布或者均匀分布生成随机数&#xff09; 前向传播&#xff1a; 前向传播中&#xff0c;模型计算权重矩阵和输入数据的结果&#xff0c;得…

第1关:JDBC程序设计

第1关&#xff1a;JDBC程序设计 任务描述相关知识JDBC程序设计JDBC主要功能JDBC主要接口和函数JDBC应用程序开发实例编程要求代码参考 任务描述 本关任务&#xff1a;使用 JDBC 往表中插入数据。 相关知识 为了完成本关任务&#xff0c;你需要掌握&#xff1a; 1.JDBC 主要功…

SM3_CNC,轴组,G代码解析,CNC运动控制

硬件要求&#xff1a; 中型PLC&#xff08;汇川AM600&#xff0c;禾川HCQ0&#xff09;&#xff0c;且带 SM3_CNC.library 库&#xff08;3.5.6支持离线仿真&#xff09; G代码标准&#xff1a; DIN66025 DIN66025-1标准G0 运动定位 G1 线性插补 G2 顺圆插补 G3 …

决策树案例以及决策树可视化

一、案例背景 泰坦尼克号沉没是历史上最臭名昭著的沉船之一。1912年4月15日&#xff0c;在她的处女航中&#xff0c;泰坦尼克号在与冰山相撞后沉没&#xff0c;在2224名乘客和机组人员中造成1502人死亡。在这个案例中&#xff0c;我们要求完成对哪些人可能存活的分析。特别是&…

【C++系列Pn】引用——背刺指针的神秘刺客“吃我一棍”

前言 大家好吖&#xff0c;欢迎来到 YY 滴 C系列 &#xff0c;热烈欢迎&#xff01;如标题所示&#xff0c;本章主要内容主要来侃侃“引用”这个刺客&#xff01;如下就是大纲啦~ 一.引用 1.含义与特点 引用&#xff0c;即取别名。它的最大特点是编译器不会为引用变量而开辟空间…

202313读书笔记|《山居七年》————我只想在广袤璀璨的星河里享受生的鲜活,独自飞,游走

202313读书笔记|《山居七年》————我只想在广袤璀璨的星河里享受生的鲜活&#xff0c;独自飞&#xff0c;游走 《山居七年》 作者张二冬&#xff0c;选择隐士山居是一种很自由随性的生活态度&#xff0c;我觉得这不是普通人可以拥有的&#xff0c;比如我&#xff0c;并未入…

Office project 2007安装

哈喽&#xff0c;大家好。今天一起学习的是project 2007的安装&#xff0c;Microsoft Office project项目管理工具软件&#xff0c;凝集了许多成熟的项目管理现代理论和方法&#xff0c;可以帮助项目管理者实现时间、资源、成本计划、控制。有兴趣的小伙伴也可以来一起试试手。…

xmind思维导图转成禅道测试用例

xmind思维导图用来编写用例胜在效率高&#xff0c;可以快速的理清楚需求。缺点在于没法上传禅道&#xff0c;但是公司有要求每次迭代要有禅道的测试用例。直接写禅道的测试用例的话&#xff0c;又很耗时&#xff0c;效率低下&#xff0c;与提高人效的公司年度战略不符&#xff…

apache虚拟主机头的实现方式

目录 一&#xff1a;基于不同的IP地址 二&#xff1a;基于不同的端口 三&#xff1a;基于不同的域名 一&#xff1a;基于不同的IP地址 步骤一&#xff1a;修改主配置文件 vim /usr/local/apache/conf/httpd.conf 声明监听不同的IP地址的80端口 Listen 192.168.2.20:80 Listen…

ChatGPT工作提效之使用python开发对接百度地图开放平台API的实战方案(批量路线规划、批量获取POI、突破数量有限制、批量地理编码)

ChatGPT工作提效系列文章目录 ChatGPT工作提效系列 ChatGPT工作提效之初探路径独孤九剑遇强则强ChatGPT工作提效之在程序开发中的巧劲和指令(创建MySQL语句、PHP语句、Javascript用法、python的交互)ChatGPT工作提效之生成开发需求和报价单并转为Excel格式ChatGPT工作提效之小…

URLConnection(四)

文章目录 1. 配置客户端请求HTTP首部2. 向服务器写入数据3. URLConnection的安全考虑4. HttpURLConnection 1. 配置客户端请求HTTP首部 HTTP客户端&#xff08;如浏览器&#xff09;向服务器发送一个请求行和一个首部&#xff0c;如下&#xff1a; web服务器可以根据这个信息…

Visual Studio 远程调试工具(Remote Debugger)使用方法

一、关于Remote Debugger 当项目在测试环境上有bug&#xff0c;需要运行代码调试一下&#xff0c;这时就需要在测试环境上安装一个调试工具&#xff08;Remote Debugger&#xff09;&#xff0c;然后在本地运行代码&#xff0c;远程链接到测试环境服务器来调试代码&#xff1b…