首页 > 编程语言 >第十五届蓝桥杯大赛软件赛省赛 C/C++ 大学 A 组

第十五届蓝桥杯大赛软件赛省赛 C/C++ 大学 A 组

时间:2024-04-16 17:16:02浏览次数:20  
标签:CI include smx 赛省赛 C++ 蓝桥 int now define

Preface

答辩圈钱杯,去年省赛的题好歹还有些有意思的题(指杜教筛),今年变成煞笔题开会了是吧

两个小时多一点就全写完了,然后开始给后面三题写对拍(结果发现其实都没写挂纯在浪费时间)

考完感觉AK有望,结果后面发现最后一题漏看条件了,苦露西

而且中间EF两题全偷懒开__int128了,反正用下发的编译器开C++11是能跑的,也看的网上有其他人用了__int128,希望别CE的说


试题 A: 艺术与篮球

签到,直接枚举判断就好了,话说这种日期处理的相关题是蓝桥杯特色环节吗

答案应该是3228,但两个填空题比赛时候的代码不知道为什么被我弄没了,没法贴在这里的说


试题 B: 五子棋对弈

还是大力枚举题,但要注意白子/黑子的数量应该是\(13/12\),看到好多错的就是忘记判这个了

答案应该是3126376


试题 C: 训练士兵

刚开始以为答案关于组团训练的次数有三分性之类的,后面看了眼数据范围原来可以直接枚举组团训练的次数\(t\)

然后需要维护的就是\(c_i>t\)的士兵的\(\sum c_i\times p_i\)和\(\sum p_i\)的值了,拿个后缀和随便维护一下

#include<cstdio>
#include<iostream>
#define int long long
#define RI register int
#define CI const int&
using namespace std;
const int N=1e6+5;
int n,S,p,c,mx_c,spx[N],sfx[N];
signed main()
{
	RI i; for (scanf("%lld%lld",&n,&S),i=1;i<=n;++i)
	scanf("%lld%lld",&p,&c),mx_c=max(mx_c,c),spx[c]+=p,sfx[c]+=c*p;
	for (i=mx_c-1;i>=1;--i) spx[i]+=spx[i+1],sfx[i]+=sfx[i+1];
	int ans=sfx[1]; for (i=1;i<=mx_c;++i)
	ans=min(ans,i*S+(sfx[i]-spx[i]*i));
	return printf("%lld",ans),0;
}

试题 D: 团建

据说是个傻逼题,但有铸币做不来怎么办

没关系直接大力Hash就完事,对两棵树的每个根到当前点的路径做Hash,然后拿个map维护下匹配即可

写了双Hash应该也不会挂,自从用了这份模数后好像都没被卡过Hash

#include<cstdio>
#include<iostream>
#include<vector>
#include<set>
#define RI register int
#define CI const int&
using namespace std;
const int N=200005,mod1=998244353,mod2=1e9+7;
int n,m,x,y,a[N],b[N],ans; vector <int> A[N],B[N];
struct Hasher
{
	int x,y;
	inline Hasher(CI X=0,CI Y=0)
	{
		x=X; y=Y;
	}
	friend inline bool operator < (const Hasher& A,const Hasher& B)
	{
		return A.x!=B.x?A.x<B.x:A.y<B.y;
	}
	friend inline Hasher operator + (const Hasher& A,const Hasher& B)
	{
		return Hasher((A.x+B.x)%mod1,(A.y+B.y)%mod2);
	}
	friend inline Hasher operator - (const Hasher& A,const Hasher& B)
	{
		return Hasher((A.x-B.x+mod1)%mod1,(A.y-B.y+mod2)%mod2);
	}
	friend inline Hasher operator * (const Hasher& A,const Hasher& B)
	{
		return Hasher(1LL*A.x*B.x%mod1,1LL*A.y*B.y%mod2);
	}
}; set <Hasher> rst;
const Hasher seed=Hasher(31,131);
inline void DFS1(CI now=1,CI fa=0,Hasher pre=Hasher())
{
	pre=pre*seed+Hasher(a[now],a[now]); rst.insert(pre);
	for (auto to:A[now]) if (to!=fa) DFS1(to,now,pre);
}
inline void DFS2(CI now=1,CI fa=0,CI dep=1,Hasher pre=Hasher())
{
	pre=pre*seed+Hasher(b[now],b[now]);
	if (rst.count(pre)) ans=max(ans,dep);
	for (auto to:B[now]) if (to!=fa) DFS2(to,now,dep+1,pre);
}
int main()
{
	RI i; scanf("%d%d",&n,&m);
	for (i=1;i<=n;++i) scanf("%d",&a[i]);
	for (i=1;i<=m;++i) scanf("%d",&b[i]);
	for (i=1;i<n;++i) scanf("%d%d",&x,&y),A[x].push_back(y),A[y].push_back(x);
	for (i=1;i<m;++i) scanf("%d%d",&x,&y),B[x].push_back(y),B[y].push_back(x);
	return DFS1(),DFS2(),printf("%d",ans),0;
}

试题 E: 成绩统计

首先一眼二分答案\(x\),考虑如何check(x)

不难发现对于\(1\sim x\)这段前缀,先将所有数排个序,然后每次选相邻的\(k\)个一定是最优的

但计算方差的时候显然直接按照定义来不好处理,我们用\(D(x)=E(X^2)-[E(x)]^2\)转化一下就很容易用前缀和处理了

但要注意把比较的时候分母全乘到分子上时会爆long long,需要开__int128

#include<cstdio>
#include<iostream>
#include<algorithm>
#define RI register int
#define CI const int&
using namespace std;
const int N=100005;
int n,k,T,a[N],b[N]; long long pfx[N],pfx2[N];
inline bool check(CI x)
{
	RI i; for (i=1;i<=x;++i) b[i]=a[i]; sort(b+1,b+x+1);
	for (i=1;i<=x;++i) pfx[i]=pfx[i-1]+b[i],pfx2[i]=pfx2[i-1]+1LL*b[i]*b[i];
	for (i=k;i<=x;++i)
	{
		long long sum=pfx[i]-pfx[i-k],sum2=pfx2[i]-pfx2[i-k];
		if ((__int128)(sum2)*k-(__int128)(sum)*sum<(__int128)(T)*k*k) return 1;
	}
	return 0;
}
int main()
{
	RI i; for (scanf("%d%d%d",&n,&k,&T),i=1;i<=n;++i) scanf("%d",&a[i]);
	int l=k,r=n,mid,ret=-1; while (l<=r)
	if (check(mid=l+r>>1)) ret=mid,r=mid-1; else l=mid+1;
	return printf("%d",ret),0;
}

试题 F: 因数计数

感觉算是本场最难的一个题了,我当时是看一眼觉得有点烦然后直接跳了,写完后面两个一眼题后回头写的

刚开始的做法是考虑确定四元组\((i,j,k,l)\)中的前两项再计数,但感觉要讨论很多并且复杂度也不好优化

后面考虑先枚举确定\(i,k\),因为它们有倍数关系所以直接枚举复杂度是\(O(n\log n)\)的(假设\(n\)和值域同阶)

然后我们要考虑的就是当少了确定的这两个数后,剩下的有倍数关系的数对的数量

这个很容易想到容斥计算,用初始时全局的倍数关系数对的数量减去\(i,k\)各自带来的影响即可

注意需要分\(i\)是否等于\(k\)两种情况来讨论计算,代码还是很好写的

(PS:最后如果所有数都相同答案就是\(A_n^4\),会爆long long,因此又要开__int128

#include<cstdio>
#include<iostream>
#define int long long
#define RI register int
#define CI const int&
using namespace std;
const int N=100005;
int n,m,x,c[N],f[N],all; __int128 ans;
inline void write(__int128 x)
{
	if (x==0) return (void)(putchar('0'));
	if (x>9) write(x/10); putchar(x%10+'0');
}
signed main()
{
	//freopen("F.in","r",stdin); freopen("F.out","w",stdout);
	RI i,j; for (scanf("%lld",&n),i=1;i<=n;++i)
	scanf("%lld",&x),++c[x],m=max(m,x);
	for (i=1;i<=m;++i) if (c[i])
	for (j=i*2;j<=m;j+=i) if (c[j])
	f[i]+=c[j],f[j]+=c[i],all+=c[i]*c[j];
	for (i=1;i<=m;++i) all+=c[i]*(c[i]-1);
	for (i=1;i<=m;++i) if (c[i])
	{
		auto delta=[&](CI x,CI d)
		{
			return x*(x-1)-(x-d)*(x-d-1);
		};
		if (c[i]>=2) ans+=(__int128)(c[i])*(c[i]-1)*(all-delta(c[i],2)-f[i]*2);
		for (j=i*2;j<=m;j+=i) if (c[j]) ans+=(__int128)(c[i])*c[j]*(all-delta(c[i],1)-delta(c[j],1)-f[i]-f[j]+1);
	}
	return write(ans),0;
}

试题 G: 零食采购

这TM绝对是很久之前的NOIP原题了,我感觉我以前肯定做过,而且颜色数\(20\)也是很经典了

刚开始看完题以为要写树上莫队了,感觉这东西讨论起来有点小复杂,很久没写都快忘了

后面一看数据范围\(c_i\le 20\)直接乐了,直接把每种颜色状压然后合并的时候或一下即可

本来以为要写树剖的以为又要被板子题腐乳了,后面一想妈的又没有修改直接写个倍增完事

#include<cstdio>
#include<iostream>
#include<vector>
#define RI register int
#define CI const int&
using namespace std;
const int N=100005;
int n,q,c[N],x,y,cnt[(1<<20)+5]; vector <int> v[N];
int anc[N][20],col[N][20],dep[N];
inline void DFS(CI now=1,CI fa=0)
{
	dep[now]=dep[fa]+1; anc[now][0]=fa; col[now][0]=(1<<c[now]);
	for (RI i=0;i<19;++i) if (anc[now][i])
	anc[now][i+1]=anc[anc[now][i]][i],col[now][i+1]=col[now][i]|col[anc[now][i]][i]; else break;
	for (auto to:v[now]) if (to!=fa) DFS(to,now);
}
inline int getLCA(int x,int y)
{
	RI i; if (dep[x]<dep[y]) swap(x,y);
	for (i=19;i>=0;--i) if (dep[anc[x][i]]>=dep[y]) x=anc[x][i];
	if (x==y) return x;
	for (i=19;i>=0;--i) if (anc[x][i]!=anc[y][i]) x=anc[x][i],y=anc[y][i];
	return anc[x][0];
}
inline int getcol(int x,CI y)
{
	int ret=0; for (RI i=19;i>=0;--i)
	if (dep[anc[x][i]]>=dep[y]) ret|=col[x][i],x=anc[x][i];
	return ret|(1<<c[y]);
}
int main()
{
	//freopen("G.in","r",stdin); freopen("G.out","w",stdout);
	RI i; for (scanf("%d%d",&n,&q),i=1;i<=n;++i) scanf("%d",&c[i]),--c[i];
	for (i=1;i<n;++i) scanf("%d%d",&x,&y),v[x].push_back(y),v[y].push_back(x);
	for (i=1;i<(1<<20);++i) cnt[i]=cnt[i>>1]+(i&1);
	for (DFS(),i=1;i<=q;++i)
	{
		scanf("%d%d",&x,&y); int z=getLCA(x,y);
		printf("%d\n",cnt[getcol(x,z)|getcol(y,z)]);
	}
	return 0;
}

试题 H: 封印宝石

这种字典序最大/最小的题目都是一套流程,按位枚举然后贪心选,这题也不例外

从左往右枚举当前位置\(i\),考虑能放入当前盒子的宝石范围为\([i,i+k]\),那么显然从里面挑一个最大的即可

如果有多个最大的那么显然先拿靠左的一定更优,然后随便写个线段树维护下就行了

结果赛后才发现有个“相邻的两个盒子的宝石不能相同”,那就再额外维护个严格次大值以及其最左的位置即可

(PS:本题代码在赛后改过,加上了找次大值的部分,但很奇怪在民间数据的dashOJ上还是无法通过,合理推测是造的数据锅了,因为除了admin好像没一个过的)

#include<cstdio>
#include<iostream>
#define RI register int
#define CI const int&
using namespace std;
const int N=100005;
int n,k,a[N],ans[N];
struct ifo
{
	int mx,mxp,smx,smxp;
	inline ifo(CI MX=-1e9,CI MXP=0,CI SMX=-2e9,CI SMXP=0)
	{
		mx=MX; mxp=MXP; smx=SMX; smxp=SMXP;
	}
};
class Segment_Tree
{
	private:
		ifo O[N<<2];
		inline ifo merge(const ifo& A,const ifo& B)
		{
			ifo C; if (A.mx>B.mx)
			{
				C.mx=A.mx; C.mxp=A.mxp;
				if (A.smx>=B.mx) C.smx=A.smx,C.smxp=A.smxp;
				else C.smx=B.mx,C.smxp=B.mxp;
			} else if (A.mx<B.mx)
			{
				C.mx=B.mx; C.mxp=B.mxp;
				if (A.mx>=B.smx) C.smx=A.mx,C.smxp=A.mxp;
				else C.smx=B.smx,C.smxp=B.smxp;
			} else
			{
				C.mx=A.mx; C.mxp=A.mxp;
				if (A.smx>=B.smx) C.smx=A.smx,C.smxp=A.smxp;
				else C.smx=B.smx,C.smxp=B.smxp;
			}
			return C;
		}
	public:
		#define TN CI now=1,CI l=1,CI r=n
		#define LS now<<1,l,mid
		#define RS now<<1|1,mid+1,r
		inline void build(TN)
		{
			if (l==r) return (void)(O[now]=ifo(a[l],l));
			int mid=l+r>>1; build(LS); build(RS);
			O[now]=merge(O[now<<1],O[now<<1|1]);
		}
		inline ifo query(CI beg,CI end,TN)
		{
			if (beg<=l&&r<=end) return O[now]; int mid=l+r>>1; ifo ret;
			if (beg<=mid) ret=merge(ret,query(beg,end,LS));
			if (end>mid) ret=merge(ret,query(beg,end,RS)); return ret;
		}
		inline void updata(CI pos,TN)
		{
			if (l==r) return (void)(O[now]=ifo(-1,l)); int mid=l+r>>1;
			if (pos<=mid) updata(pos,LS); else updata(pos,RS);
			O[now]=merge(O[now<<1],O[now<<1|1]);
		}
		#undef TN
		#undef LS
		#undef RS
}SEG;
int main()
{
	//freopen("H.in","r",stdin); freopen("H.out","w",stdout);
	RI i; for (scanf("%d%d",&n,&k),i=1;i<=n;++i) scanf("%d",&a[i]);
	for (SEG.build(),ans[0]=-1,i=1;i<=n;++i)
	{
		int pos=SEG.query(i,min(n,i+k)).mxp;
		if (a[pos]==-1) { ans[i]=-1; continue; }
		if (ans[i-1]==-1||a[pos]!=ans[i-1])
		{
			ans[i]=a[pos]; a[pos]=-1;
			k-=(pos-i); SEG.updata(pos);
		} else
		{
			pos=SEG.query(i,min(n,i+k)).smxp;
			if (a[pos]==-1) { ans[i]=-1; continue; }
			ans[i]=a[pos]; a[pos]=-1;
			k-=(pos-i); SEG.updata(pos);
		}
	}
	for (i=1;i<=n;++i) printf("%d%c",ans[i]," \n"[i==n]);
	return 0;
}

Postscript

感觉今年只要EF不要因为__int128CE还是随便拿省一的说

但不管怎么说既然来打圈钱杯了目标肯定就是国一了,去年沟槽的国二第三名真是太难受了

标签:CI,include,smx,赛省赛,C++,蓝桥,int,now,define
From: https://www.cnblogs.com/cjjsb/p/18138661

相关文章

  • 华为实习4.10机考第二题C++代码
    考的是简单的并查集这道题考法就是并查集,若两个图片相似度大于0,则将他们放到一个家族中,同时维护家族的相似度总和。注意M矩阵是对称矩阵,所以需要避免重复维护相似度,因此可以只针对M矩阵的下三角矩阵或上三角矩阵中的连接块,计算相似度总和;或考虑整个M矩阵,然后相似度总和除......
  • C++发票识别、发票查验接口示例,您的“发票管理专家”
    发票识别+发票查验接口。当财务人员在进行发票的数字化管理时,仅需一键上传发票图片,翔云发票识别接口即可快速、精准对发票的全票面信息进行提取,翔云发票查验接口可根据识别接口提取的发票信息实时联网进行真伪查验。助财务工作者从发票海洋中解脱出来,提升发票管理效率与准确率......
  • C++身份核验接口代码、身份证OCR、身份证实名认证API
    实名认证是什么意思呢?一般指的是对用户资料真实性进行的验证审核,这样有利于建立完善且可靠的互联网环境。如果交易双方使用的都是虚假信息,那么在诸多环节会存在很大的风险。另外,还有游戏平台对玩家进行实名认证,防止未成年人注册。实名认证有利于网络绿化,所以在互联网发展......
  • 结对编程 c++语言实现四则运算练习题
    结对同学:2252813程序要求:两个运算符,100以内的数字,不需要写答案。需要检查答案是否正确,并且保证答案在0-100之间通过阅读题目要求,我们决定使用c++语言完成编程,需要满足两个功能,首先生成一个包含两个运算符的算式,参与运算的数字在100之内。下一步检查答案是否正确,并且保证答......
  • C/C++项目中.h和.inc文件区别
    原问题:Differencebetween.hfilesand.incfilesincC/C++的标准惯例是将class、function的声明信息写在.h文件中。.c文件写class实现、function实现、变量定义等等。然而对于template来说,它既不是class也不是function,而是可以生成一组class或function的东西。编译器(compiler......
  • C++动态内存分配/malloc/new
    0前言这部分确实是面试老八股了,不过我还是记录一下1内存分区在C语言中,将内存分为程序代码区+数据区,其中数据区又分为静态存储区和动态存储区在C++中,分为五种:动态存储区:栈区:存放局部变量,由编译器自动分配释放,程序员不能操作堆:由程序员使用malloc/new申请,用free/delete......
  • 结对编程-C++四则运算
    合作伙伴:22528071.项目要求要求实现四则运算练习题。这个程序有很多种实现方式:·C/C++·C#/VB.net/Java.Excel·UnixShell.Emacs/Powershell/Vbscript.Perl·Python·两个运算符,100以内的数字,不需要写答案。·需要检查答案是否正确,并且保证答案在0……100......
  • C++ 默认参数与引用传递:语法、用法及示例
    C++默认参数默认参数概述在C++中,函数参数可以拥有默认值。这意味着,在调用函数时,如果省略了某个参数,那么将使用为该参数指定的默认值。设置默认参数默认参数值使用等号=符号进行设置,位于参数声明的类型之后。例如:voidmyFunction(stringcountry="Norway");在这个例......
  • 【2024蓝桥B组】小球反弹
    小球反弹题目题目分析一个比较绕脑的数学问题。。。首先:小球能过从左上角出发,然后回到左上角,那么其x方向的路径长度则为2k1x,y方向的路径长度则为2k2y。其次,我们得知其x与y的速度比值为15:17,由公式:时间*速度=路程可得:t*dx=2k1x,t*dy=2k2y然后,通过简单的数学变换,我们可以得出:k......
  • C++_内存模型和函数以及类
    C++内存模型函数函数与编译器类成员变量class内部通过 static修饰变量时,表示该变量为静态成员变量,必须在类外定义 staticconst修饰变量时,表示该变量为静态成员常量,可以在类内初始化,或者在类外初始化 staticconstexpr修饰变量时,表示该......