全国大学生算法竞赛秋季赛习题

举报
irrational 发表于 2022/01/17 23:30:25 2022/01/17
【摘要】 Problem A 智慧果 题面 已知序列 a: a 1 ...

Problem A 智慧果

题面
已知序列 a:
a 1 = 1 , a 2 = 2 , a 3 = 3 a_1=1,a_2=2,a_3=3 a1=1,a2=2,a3=3
a i = a i − 1 a i − 2 a i − 3 + a i − 1 + a i − 2 + a i − 3 a_i=a_{i−1}a_{i−2}a_{i−3}+a_{i−1}+a_{i−2}+a_{i−3} ai=ai1ai2ai3+ai1+ai2+ai3
a 1000 a_{1000} a1000 对 100000 取模的值。

题解
暴 力 计 算 每 一 项 对 100000 取 模 的 值 即 可 。 暴力计算每一项对 100000 取模的值即可。 100000
时 间 复 杂 度 O ( n ) , 其 中 n 为 项 数 。 时间复杂度 O(n),其中 n 为项数。 O(n)n

代码

#include<bits/stdc++.h>
using namespace std;
#define int long long
inline int read(){//经典了,竞赛的手动读入模板,需要记忆
   int s=0,w=1;
   char ch=getchar();
   while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
   while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
   return s*w;
}
const int p=100000;
// int qp(int x,int y)
// {
// 	int res=1;
// 	for(int t=x; y; y>>=1,t=t*t%p) if(y&1) res=res*t%p;
// 	return res;
// }//快速幂模板,写着玩玩,在这题不用
int a[100003];
signed main()
{
	a[1]=1;
	a[2]=2;
	a[3]=5;//初始化
	for(int i=4; i<=1000; ++i)
	{
		a[i]=a[i-1]*a[i-2]*a[i-3]+a[i-1]+a[i-2]+a[i-3];//带入公式
		a[i]%=p;//暴力取模
	}
	printf("%lld\n",a[1000]);
	return 0;
}

Problem B Xanadu#

题面

给 定 一 个 n × n 的 01 矩 阵 给定一个 n×n 的 01 矩阵 n×n01 和 n 个 点 的 图 。 你 可 以 花 费 1 的 代 价 和 n 个点的图。你可以花费 1 的代价 n1 将 矩 阵 中 的 一 个 1 变 成 0 。 将矩阵中的一个 1 变成 0。 10
操 作 完 成 后 , 记 第 i 行 从 左 到 右 第 一 个 为 1 的 位 置 为 j , 操作完成后,记第 i 行从左到右第一个为 1 的位置为 j, i1j 则 在 图 上 从 i 到 j 之 间 连 一 条 有 向 边 。 则在图上从 i 到 j 之间连一条有向边。 ij
(言下之意,为利用稀疏矩阵表示拓扑图)

问至少要花费多少代价,才能让图上存在一条从 1 到 n 的路径,如果无法达成输出 −1。

n ≤ 300 n≤300 n300

题解

基环树:无向图,一个环,环上每个点都是树根
在这里插入图片描述

不难发现最后得到的一定是一棵基环树,因此如果有路径,必然存在一条无环的路径,即每个点仅经过一次。
我们对于矩阵建图。假设第 i i i 行的第 j j j 个位置是该行第 k 个 1 k 个 1 k1,我们就从 i 到 j 建 一 条 费 用 为 k − 1 i 到 j 建一条费用为 k−1 ijk1 的边。

不难发现,最后得到的每条从 1 到 n 的路径的边权总和就是这个方案要花费的代价,因此直接在原图上跑最短路即可。

时间复杂度 O ( n 2 ) O(n^2) O(n2) O ( n 2 l o g n ) O(n^2logn) O(n2logn)
简而言之,就是最短路径问题!
注意本题是有向图,因此矩阵不是对称矩阵。

样例

输入

4
0 1 0 0
0 0 1 0
0 0 0 1
0 0 0 0

输出

0//因为已经连通了
代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
inline int read(){//读入数据的模板
    int s=0,w=1;
    char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
    while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
    return s*w;
}
priority_queue<pair<int,int>,vector<pair<int,int>>,greater<pair<int,int>> > q;//把STL用到极致了
vector<pair<int,int> > v[1000003];
int dis[1000003];
bool vis[1000003];
signed main()//int main的另一种写法
{
    int n=read();//nxn矩阵
    int s=1;
    memset(dis,0x3f,sizeof(dis));//初始化距离为最大值
    for(int i=1; i<=n; i++) 
	{
		int s=0;
		for(int j=1;j<=n;j++)
		{
			int x=read();
			if(x==0)continue;
			v[i].push_back(make_pair(j,s));//读入某列,然后是第几个,
			//这个第几个是要干嘛呢?
			s++;
		}
	}
    dis[s]=0/*最后点数为什么是0?*/,q.push(make_pair(0,s));
    while(!q.empty())
    {
    	int x=q.top().second;
    	q.pop();
    	if(vis[x]) continue;
    	vis[x]=1;
    	for(pair<int,int> y:v[x]) 
    		if((!vis[y.first])&&dis[y.first]>dis[x]+y.second) 
    			dis[y.first]=dis[x]+y.second,
    			q.push(make_pair(dis[y.first],y.first));
    }
    	if(dis[n]>1e12) puts("-1");
    	else printf("%lld\n",dis[n]);
	return 0;
}

Problem C 这是一道大难题

题面

给定一张图,求其必须包含给定一条边的最小生成树。
n ≤ 1 0 5 , m ≤ 2 × 1 0 5 n≤10^5,m≤2×10^5 n105,m2×105

题解

直接先加入这条边,然后跑 K r u s k a l Kruskal Kruskal算法即可。
正确性显然。

时间复杂度为 O ( m l o g m + n α ( n ) ) O(mlogm+nα(n)) O(mlogm+nα(n))

代码

#pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,avx2,tune=native")
/* 编译优化的奇技淫巧
1 #pragma comment(linker, "/stack:200000000")
2 #pragma GCC optimize("Ofast,no-stack-protector")
3 #pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,tune=native")
4 #pragma GCC optimize("unroll-loops")
*/
#include <stdio.h>
#include <string.h> 
#include <algorithm>
#include <bitset>
#define od(x) printf("%d",x)
#define odb(x) printf("%d ",x)
#define odl(x) printf("%d\n",x)
#define odp(x,y) printf("%d %d\n",x,y)
#define ol(x) puts("")
#define old(x) printf("%lld",x)
#define oldb(x) printf("%lld ",x)
#define oldl(x) printf("%lld\n",x)
#define oldp(x,y) printf("%lld %lld\n",x,y)//plus
#define rg(x) for(int i=1;i<=(x);i++){
#define gr }
#define rrg(x) for(int i=0;i<(x);i++)
#define rdln(a) a[i]=read();
#define rdln0(a,x) rrg(x) rdln(a) gr
#define rdln1(a,x) rg(x) rdln(a) gr
#define int long long
inline int read()//自定义一个读入
{
	int num=0,f=1;char c=getchar();
	while(c<48||c>57){if(c=='-')f=-1;c=getchar();}
	while(c>47&&c<58)num=num*10+(c^48),c=getchar();
	return num*f;
}
inline int re1d()
{
	char c=getchar();
	while(c<48||c>49)c=getchar();
	return c&1;
}
inline int min(int a,int b){return a>b?b:a;}
inline int max(int a,int b){return a<b?b:a;}
int fa[200005];
inline int find(int x)
{
	return x==fa[x]?x:fa[x]=find(fa[x]);
}
inline int uni(int x,int y)
{
	int fx=find(x),fy=find(y);
	if(fx==fy)return 0;
	fa[fx]=fy;
	return 1;
}
struct e{
	int u,v,w;
	bool operator<(const e &b)const
	{
		return w<b.w;
	}
}a[200005];
signed main()
{
	int n=read(),m=read();
	long long c=0;
	for(int i=1;i<=n;i++)fa[i]=i;
	for(int i=1;i<=m;i++)a[i].u=read(),a[i].v=read(),a[i].w=read();
	int x=read();
	c+=uni(a[x].u,a[x].v)*a[x].w;
	std::sort(a+1,a+1+m);
	for(int i=1;i<=m;i++)c+=uni(a[i].u,a[i].v)*a[i].w;
	oldl(c);
	return 0;
}

Problem D zeal

题面

给 定 长 度 为 n 的 序 列 a , m 次 求 [ l , r ] 中 出 现 k 次 的 元 素 数 量 。 给定长度为 n的序列 a,m 次求 [l,r] 中出现 k 次的元素数量。 nam[l,r]k

n , m , a i ≤ 4 × 1 0 4 n,m,a_i≤4×10^4 n,m,ai4×104

题解

直接上莫队算法即可。
在这里插入图片描述在这里插入图片描述
在这里插入图片描述在这里插入图片描述在这里插入图片描述#### 样例
输入

10 2
1 2 3 1 1 2 1 2 3 1
1 5 3
2 9 3

输出

1
2

时间复杂度 O ( n m ) O(n\sqrt{m}) O(nm

文章来源: blog.csdn.net,作者:irrationality,版权归原作者所有,如需转载,请联系作者。

原文链接:blog.csdn.net/weixin_54227557/article/details/120923053

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。