NOIP历年初赛及模拟题

常识题

1.五个本质不同的点在没有重边或者自环的情况下,组成不同的无向图的个数是()

边数为5*4/2=10.对于每一条边,我们都有选或不选,答案为2^10=1024

2.同时扔出 𝑘 枚完全相同的六面骰子,每个骰子上有 1 到 6 的数字。将 得到的点数排序后,有( )种不同的结果?

题目等价与问你每个数字出现了多少次,等价于x1+x2+x3+x4+x5+x6=k的非负整数解的个数

等价于x1+x2+x3+x4+x5+x6=k+6的正整数解的个数。隔板法即可

3.定义 mod 为取模运算,𝑛! = 1 ⋅ 2 ⋅ 3 ⋯ 𝑛,则下式的值为( )。 ((1 + 1/2 + 1/3 + 1/4 ⋯ 1/10086) ⋅ (10085!) + 10081) mod 10086

每一项和!10085消后还是10086的倍数。举例:1/2!10086=1 * 3 * 4 * ······5042 * 5044 * ······10085,依然有33362.所以答案为10081%10086

4.大多数计算机病毒主要造成计算机软件和数据的损坏

5.ASCII编码是7位二进制编码

6.操作系统是对应用程序进行管理的软件

7.Celeron不是一个操作环境系统

8.要使用putchar函数实现向显示器输出字符“A”,可以使用putchar(65).里面只能加数字并且要是ASCII

9.两个指针都指向同一个数组中的元素可以相减,但不能相加,不影响之后指向其它变量或改变其值

10.现有变量a,b,c,d取值范围为[0,15]。假设每个值出现的概率相同,则表达式a xor b xor c xor d xor 的值能被3整除的概率是

分类讨论0,3,6,9,12,15,这里有个结论,就是异或值取到[0,16]的任何一个值得概率都是相等的。所有答案为6/16=3/8

搜索“从1,...,99,2015这100个数中任意选择若干个数”,推导太难了

11.某递归算法的时间复杂度关系如下:

当n=1时,T(n)=1

当n>1时,T(n)=2*T(n/2)+1

设n=2^k

T(n)=2k*T(1)+2k-1=2* * n - 1

12.一课完全二叉树有501个叶子节点,则至少有()个节点

在完全二叉树中有一个性质就是n0=n2+1.n=n0+n1+n2=1001+n1,n1为0或者1所以有n>=1001

一颗深度为k二叉树,有n个节点,然后,也对这棵树进行编号,如果所有的编号都和满二叉树对应,那么这棵树是完全二叉树。

13.中国计算机学会于1984年创办全国青少年计算机程序竞赛

14.某计算机的CPU和内存之间的地址总线宽度是32

因为已经是位了所以不用除8,答案为2^32/1024/1024/1024=4

一、会话层

           提供的服务可使应用建立和维持会话,并能使会话获得同步
二、表示层

           主要作用是为异种机通信提供异种公共语言,以便能进行互操作。这种类型的服务之所以需要,是因为不同的计算机体系结构使用的数据表示方法不同。

          例如,IBM主机使用EBCDIC编码,而大部分PC机使用的是ASCII码。在这种情况下,便需要表示层来完成这种转换。

三、应用层

   包含通常使用的协议:

       HTTP(Hyper text Transfer Protocol)协议:超文本传输协议使用TCP的80端口

       FTP(File Transfer Protocol)文本传输协议

       SMTP(Simple Mail Transfer Protocol)简单邮件传输协议,TCP是我25端口用户发邮件。

       POP3(Post Office Protocol version3)邮局协议版本3,TCP的110号端口,用于收邮件的。

       DNS(Domain Name System)域名解析协议。使用TCP和UDP的53号端口,作用是把www的域名解析成IP地址。


四、传输层

      传输层的相关协议:

            TCP(Transmission control protocol 传输控制协议)

            UDP(User Datagram Protcol用户数据报协议)

 

五、网络层

一、主要功能:


        涉及的协议有IP、IPX等,网络层的设备必须能识别出网络层的地址,如路由器,三层交换机等都可以根据IP地址做出路径的选择,他们都属于网络层的设备。

        路由器是一种链接多个网络或者网段的设备,它能将不同网络或网段之间的数据进行“翻译”,使它们可以互相“读懂”对方的数据,从而构成更大的网络。它是应用于不同网段或者不同网络之间的设备。


六、数据链路层

一、功能:

1.完成网络之间相邻结点的可靠传输。

2.物理层传输的是比特流(bit),数据链路层传输的是帧(Frame)。

3.数据链路层是通过MAC地址负责主机之间数据的可靠传输。

七、物理层

1.物理层主要功能

完成相邻节点比特流之间的传输,控制数据怎样被放到传输介质上的,关心的是用什么物理信号来表示‘0’和‘1’,最初的链接是如何建立的,或者连接后是如何终止的。

19.Unicode是一种通用字符编码,他为世界上绝大部分语言设定了统一并唯一的二进制编码,以满足跨语言跨平台的文本交换

20.1946年诞生于美国宾夕法尼亚大学的ENIAC属于电子管计算机

21.寄存器是中央处理器的重要组成部分

22.为解决web应用中的不兼容问题,保障信息的顺利流通,万维网联盟(w3c)制定了一系列标准,设计HTML,XML,CSS并建议开发者遵循

23.事实上,Linux下的文件不需要扩展名。

24.对有序数组{5,13,19,21,37,56,64,75,88,92,100}进行二分查找,等概率的情况下查找成功的平均查找长度是()

56只需一次就能查找到,19,88需要两次,5和13,21和37,64和75,92和100中每组两个数一个是3另一个是4具体看程序。

全部加起来是33,33/len=33/11

25.二分图求最大边数,如12个点,就是(12/2)*(12/2)

26.正数的反码是它本身,正数的补码也是它本身,负数的反码是在原码的基础上, 符号位不变,其余各个位取反。负数的补码是其反码+1

27.二进制数-1101010的补码是?

原数的原码是11101010,反码10010101,补码是10010110

28.循环列表的优点:

  1. 没有NULL指针,不必在移动指针的时候判断指针指向的点是否为空
  2. 从任意节点出发都能遍历整个链表

29.img

T(n) = aT(n / b) + f(n)

  1. 如果f(n) < n^(log(a,b)) ,T(n) = O(n ^ (log(a,b) ) )
  2. 如果两者相等,则T(n) = O(n ^ (log(a,b) ) * log(n) )
  3. 如果f(n) > n^(log(a,b)) 则 T(n) = O(f(n))

当然,时间复杂度可以用数学的方法解出来

30.用n-1条边将n个一致的顶点连接起来的连通图的个数为n^(n-2)

5个不同节点构成的无根树有()种

无根树当成连通图处理,用cayley定理得125

程序题

1.第二十行代码改成a[y [i] ] [ 0 ] =d[i]不影响运算结果

答案是对的,原因:

#include<bits/stdc++.h>
using namespace std;
const int maxn=100001;
int N,M,K;
int x[maxn],y[maxn],d[maxn],c[maxn];
int *a[maxn];
int main(){
	cin >> N >> M >> K;
	for(int i = 0;i<K;++i){
		cin >>x[i]>>y[i]>>d[i];
		c[y[i]]++;//每列有几个数
	}
	for(int i=1;i<=M;++i){
		a[i]=new int[c[i]];//类似邻接表
	}
	for(int i=0;i<K;++i){
		*a[y[i]]=d[i];
		a[y[i]]++;//a是下标
	}
	for(int i = 1;i<=M;++i){
		a[i]=a[i]-c[i];
		for(int j=0;j<c[i];++j,++a[i])
		{
			cout<<*a[i]<<" ";
		}
	}
	//这个程序是从左到右从上到下输出每一列的数
	/*
4 5 10
1 1 3
1 2 5
1 4 8
2 3 9
3 3 6
2 4 9
2 5 10
3 1 5
3 4 8
3 2 9
输出:
3 5 5 9 9 6 8 9 8 10
	*/
	return 0;
}
/*
n阶幻方,看出来了就很简单*/
#include<iostream>
#include<iomanip>
using namespace std;
int m[101][101];
int main(){
	int a;
	cin>>a;
	int c=a*a,i=1,k=(a+1)/2;
	for(int j=1;j<=c;++j){
		m[i][k]=j;
		if(j%a==0){
			if(i==a)i=1;
			else i++;
		}else{
			if(i==1)i=a;
			else i--;
			if(k==a)k=1;
			else k++;
		}
	}
	for(int i = 1;i<=a;++i){
		for(int j=1;j<=a;++j)
			cout<<setw(5)<<m[i][j];
		cout<<endl;
	}
}

没什么用的题

#include<iostream>
#include<iomanip>
using namespace std;
int a[101],d[101];
int main(){
	int n=5;
	a[1]=d[1]=1;
	for(int i = 1;i<=n;++i){
		int s=i+1,x=0;
		for(int j=1;j<=n+1-i;++j)
		{
			int k=s+x;
			x++;
			a[j+1]=a[j]+k;
			cout<<a[j]<<" ";
		}
		cout<<"···"<<endl;
		a[1]=d[i+1]=d[i]+i;
	}
	return 0;
}

4.挺好的01背包

在遥远的国家佛罗布尼亚,嫌犯是否有罪,须由陪审团决定。陪审团是由法官从公众中挑选的。先随机挑选n 个人作为陪审团的候选人,然后再从这n 个人中选m 人组成陪审团。选m 人的办法是:控方和辩方会根据对候选人的喜欢程度,给所有候选人打分,分值从0 到20。为了公平起见,法官选出陪审团的原则是:选出的m 个人,必须满足辩方总分D和控方总分P的差的绝对值|D-P|最小。如果有多种选择方案的 |D-P| 值相同,那么选辩控双方总分之和D+P最大的方案即可。

考虑到每个候选人只有选或者不选两种情况,而且之前不是最优解的人可能之后也要被选上。所以做法是0/1背包。设f [j] [k]表示选了j个人,差值为k的D+P的最大值。

状态转移方程:f [j] [k]=max(f [j] [k],f [j−1] [k−(p[i]−d[i])]+p[i]+d[i])

最初 f [0] [0]=0其余为 -1或者 -0x3f3f3f3f 由于可能会使下标变成负数,所以增加一个修正值20m` (因为差值最多为20m,使映射区间向右平移)

#include<cstdio>
#include<cstdlib>
#include<memory>
#include<algorithm>
#include<bits/stdc++.h>
int f[30][1000];
int Path[30][1000];
int P[300];
int D[300];
int Answer[30];
int main()
{
	int i,j,k,t1,t2,n,m,nMinP_D,nCaseNo;
	nCaseNo=0;
	scanf("%d%d",&n,&m);
	while(n+m){
		nCaseNo++;
		for(i=1;i<=n;++i){
			scanf("%d%d",&P[i],&D[i]);
			memset(f,-1,sizeof(f));
			memset(Path,0,sizeof Path);
			nMinP_D=m*20;//偏移量
			f[0][nMinP_D]=0;//f[0][0]=0;
			for(j=0;j<m;++j){
				for(int k=0;k<=nMinP_D*2;++k)
				if(f[j][k]>=0){
					for(int i=1;i<=n;++i)
						if(f[j][k]+P[i]+D[i]>f[j+1][k+P[i]-D[i]])
						{
							t1=j;
							t2=k;
							while(t1>0&&Path[t1][t2]!=i){
								t2-=P[Path[t1][t2]]-D[Path[t1][t2]];
								t1--;
							}
						
						if(t1==0){//确保人员不同
							f[j+1][k+P[i]-D[i]]=f[j][k]+P[i]+D[i];
							Path[j+1][k+P[i]-D[i]]=i;
						}
					}
				}
			}
			i=nMinP_D;
			j=0;
			while(f[m][i+j]<0&&f[m][i-j]<0)j++;
			if(f[m][i+j]>f[m][i-j])
				k=i+j;
			else k=i-j;
			printf("Jury#%d\n",nCaseNo);
			printf("Best jury has value%d for prosecution and value%d for defence:\n",(k-nMinP_D+f[m][k])/2,(f[m][k]-k+nMinP_D)/2);
			for(i=1;i<=m;++i){
				Answer[i]=Path[m-i+1][k];
				k-=P[Answer[i]-D[Answer[i]]];
			}
			std::sort(Answer+1,Answer+m+1);
			for(i=1;i<=m;++i)printf("%d",Answer[i]);
			printf("\n");
			printf("\n");
			scanf("%d%d",&n,&m);
		}
	}
	return 0;
}

历年真题

2.在关系数据库中,存放在数据库中的数据的逻辑结构以( )为主。 答案:二维表

9.欧拉图 G是指可以构成一个闭回路的图,且图 G的每一条边恰好在这个闭回路上出现一次(即一笔画成)。在以下各个描述中,不一定是欧拉图的是( )。

A. 图 G 中没有度为奇数的顶点

B. 包含欧拉环游的图(欧拉环游是指通过图中每边恰好一次的闭路径)

C. 包含欧拉闭迹的图(欧拉迹是指通过图中每边恰好一次的路径)

D. 存在一条回路,通过每个顶点恰好一次

E. 本身为闭迹的图

答案为D

通过每个顶点一次没说通过每条边一次,其它选项看不懂

有向图:图连通,有一个顶点出度大入度1,有一个顶点入度大出度1,其余都是出度=入度。

无向图:图连通,只有两个顶点是奇数度,其余都是偶数度的。

17.以下断电之后仍能保存数据的有( )。

A. 硬盘

B. ROM

C. 显存

D. RAM

AB

ROM是只读存储器,RAM是随机存取存储器,显存是用来存储要处理的图形信息的部件

25.由四个不同的点构成的简单无向连通图的个数是

最多六条边,最少三条边,C(3,6)+C(4,6)+C(5,6)+C(6,6)=38

洛谷模拟题

常识题

13.最大子段和问题,即给出一个长度为n的序列a,选出其中连续且非空的一段使得这段和最大,当我们采用分治算法(不采用最优的分治方式)去计算这道题的结果时,最优平均复杂度为 B:O(n log n)

这种题真的······,贪心明明扫一遍就够了,偏要整这些东西,之前做过一道分治的是O(n)。这里说是不是最优,那可以理解成多一点但应该不到A选项那个程度,故答案选B

程序题

1.此题全对,之所以写是为了水字数

#include<bits/stdc++.h>
using namespace std;
const int maxn=1003;
int type,n,m;
char s[maxn],t[maxn];
int main(){
	scanf("%d %s %s",&type,t,s);
	n=strlen(s);m=strlen(t);
	if(type<2){
		for(int i=0;i<m;++i)
			s[i]=t[i];
	}else if(type==2){
		strcpy(s,t);
	}else{
		for(int i=0;i<m;++i){
			unsigned int code=0,pos=i;
			for(int j=1;pos<i+4;j*=100,++pos){//*100是比较关键的,只有ASCII码100以下的才能保证不乱码,猜的,这道阅读程序题是我第一个全部答对(蒙对)的题
				if(pos==m)break;
				code+=t[pos]*j;
			}
			pos=i;
			while(code!=n){
				s[pos++]=code%100;
				code/=100;
			}
		}
	}
	for(int i=0;i<n;++i)printf("%c",s[i]);
	puts("");
}

2.死伤惨重

第一题是find函数能不能取到-1.那个-1纯粹是诱惑,坚信CSP不可能白给这么简单的题目。当我们知道FIND的功能时就可以确定不可能返回-1

第二题是时间复杂度 Θ(𝑛2𝑚2),这个是对的,显然不可能会超过这个n2m2,这个似乎是上界。

第三题对于任意u,先执行front,right,和先执行right,front不一样,这个是对了的。

第四题将anchorX,anchorY,anchorZ依次更换为()时,与改变前的输出结果无异。

我猜猜吗这个六个面可以循环滚,所以只要能立方体能有原始的三个值组成就行了吧,那么D是可以滚出来的,A,B,C都不行。

第五题

image-20220912090936831

第六题

这种手动模拟题就直接摆吧,这道题有五种情况,因为向下翻的次数固定为1次。答案为A

/*
	画出六个坐标轴可知是三维空间,way1,way2分别是三维中两个平面中滚动
	w[6]代表六个面,dp[i][j][u][v]表示(i,j)点上,上,前两个面分别是(u),(v)的立方体
	权值是a[i][j]*w[底面]
	代码中right_rotate(u1)是向右滚的意思,front_rotate是向上滚,find_down就是寻找底面
*/
#include<bits/stdc++.h>
using namespace std;
const int INF=1000000000;
#define Front 0
#define Back 1
#define Left 2
#define Right 3
#define Up 4
#define Down 5
int w[6],a[1003][1003];
const int way1[]={Up,Right,Down,Left};
const int way2[]={Up,Front,Down,Back};
const int way3[]={Left,Front,Right,Back};
int get_max(int &a,int b){
	return a=max(a,b);
}
int right_rotate(int &u){
	for(int i=0;i<4;++i)
		if(u==way1[i])
			return u=way1[(i+1)%4];
	return u;
}
int front_rotate(int &u){
	for(int i=0;i<4;++i)
		if(u==way2[i])
			return u=way2[(i+1)%4];
	return u;
}
const int anchorX=Up;
const int anchorY=Front;
const int anchorZ=Right;
int find_down(int u,int v){
	if(u==Down||u==Up)return anchorX^(u==Up);
	if(v==Down||v==Up)return anchorY^(v==Up);
	for(int i=0;i<4;++i)
		if(u==way3[i])
			return anchorZ^(v==way3[(i+1)%4]);
	return -1;
}
int n,m,dp[1003][1003][6][6];
int main(){
	cin>>n>>m;
	for(int i=0;i<n;++i)
		for(int j=0;j<n;++j)
			cin>>a[i][j];
	for(int i=0;i<6;++i)
		cin>>w[i];
	for(int i=0;i<n;++i)
		for(int j=0;j<n;++j)
			for(int a=0;a<6;++a)
				for(int b=0;b<6;++b)
					dp[i][j][a][b]=-INF;
	dp[0][0][anchorX][anchorY]=a[0][0]*w[Down];
	for(int i=0;i<n;++i)
		for(int j=0;j<m;++j)
			for(int p=0;p<6;++p)
				for(int q=0;q<6;++q)
	{
		if(dp[i][j][p][q]!=!INF){
			int x=dp[i][j][p][q];
			int u1=p,v1=q;
			right_rotate(u1);
			right_rotate(v1);
			get_max(dp[i][j+1][u1][v1],x+w[find_down(u1,v1)]*a[i][j+1]);
			int u2=p,v2=q;
			front_rotate(u2);
			front_rotate(v2);
			get_max(dp[i+1][j][u2][v2],x+w[find_down(u2,v2)]*a[i+1][j]);
		}
	}
	int ans=-INF;
	for(int p=0;p<6;++p)
		for(int q=0;q<6;++q)
			ans=max(ans,dp[n-1][m-1][p][q]);
	printf("%d\n",ans);
	return 0;
}
/*
	这道题中难度两级分化,简单的可以看名字写,难的也没要想
*/
#include <bits/stdc++.h>
using namespace std;
 const int MAXN = 309;
 const int MAXM = 109;
 const int MAXP = 100000;
 typedef long long ll;
 int n, m, seed,rt,btm,s[MAXM],Len,dfncnt,full_dist,P,t;
 int lg[MAXN],dfn[MAXN],fa[MAXN],dep[MAXN], lson[MAXN];
 vector <int> e[MAXN];
 vector <int> L[MAXM],leaves;
 int F[MAXM];
 namespace LCA {
	 int st[24][MAXN];
	 int minNode(int x, int y){return dep[x]<dep[y] ? x:y;}
	 void init() {
		 for (int i = 1; i <= n; ++i) st[0][dfn[i]]=fa[i];
		 for (int i = 1; i <= lg[n]; ++i)
			 for (int j = 1; j + (1 << i) - 1 <= n; ++j)
				 st[i][j] = minNode(st[i - 1][j], st[i - 1][j + (1 
					<< (i - 1))]);
		 }
	 int lca(int u, int v) {
		 if (u == v) return u;
		 if ((u = dfn[u]) > (v = dfn[v])) swap(u, v);
		 int d = lg[v - u++];
		 return minNode(st[d][u], st[d][v - (1 << d) + 1]);
		 }
	 }
 namespace Gen {
	 mt19937 rnd;
	 int pos[MAXN], deg[MAXN];
	 vector <pair<int, int>> edges;
	 void calc() {
		 for (int i = 1; i <= n - 2; ++i)
			 ++deg[pos[i]];
		 set <int> ret; ret.clear();
		 for (int i = 1; i <= n; ++i)
			 if (deg[i] == 1) ret.insert(i);
		 for (int i = 1; i <= n - 2; ++i) {
			 int npos = *ret.begin();
			 edges.push_back(make_pair(npos, pos[i]));
			 ret.erase(ret.begin());
			 --deg[pos[i]];
			 if (deg[pos[i]] == 1)
				 ret.insert(pos[i]);
			 }
		 edges.push_back(make_pair(*ret.begin(), n));
		 }
	 void build() {
		 for (auto i : edges) {
			 int u = i.first, v = i.second;
			 e[u].push_back(v); e[v].push_back(u);
			 }
		 }
	 void generate(int seed) {
		 rnd.seed(seed);
		 edges.clear();
		 for (int i = 1; i <= n; ++i) deg[i] = 1;
		 for (int i = 1; i <= n - 2; ++i)
			 pos[i] = rnd() % n + 1;
		 calc();
		 build();
		 }
	 }
 int dfs(int u, int _fa, int &bottom) {
	 dfn[u] = ++dfncnt;
	 if (e[u].size() == 1) leaves.push_back(u);
	 lson[u] = -1; fa[u] = _fa; dep[u] = dep[_fa] + 1;
	 int maxlen = 0, dson = u, temp;
	 for (int v: e[u])
		 if (v != _fa) {
		 int p = dfs(v,u,temp);
		 if (p > maxlen) maxlen = p, lson[u]=v, dson=temp;
		 }
	 bottom = dson;
	 return maxlen + 1;
	 }
 #define dist(u, v) (dep[u]+dep[v]-2*dep[LCA::lca(u, v)])
 int v[MAXP+9], prime[MAXP + 9], prime_cnt, vis[MAXP+9];
 void prime_init(int n) {
	 prime_cnt = 0;
	 for (int i = 2; i <= n; ++i) {
		 if (!v[i]) prime[++prime_cnt] = v[i] = i;
		 for(int j=1; j <= prime_cnt && i*prime[j]<=n; ++j) {
			 if (v[i] < prime[j]) break;
			 v[i * prime[j]] = prime[j];
			 }
		 }
	 }
 vector<int> answer, gline;
 void solve() {
	 cin >> n >> m >> seed >> t;
	 lg[0] = lg[1] = 0;
	 for (int i = 2; i <= n; ++i) lg[i] = lg[i >> 1] + 1;
	 for (int i = 1; i <= n; ++i) e[i].clear();
	 leaves.clear();
	 if (!t) Gen::generate(seed);
	 else {
		 for (int i = 1, u, v; i < n; ++i) {
			 cin >> u >> v;
			 e[u].push_back(v); e[v].push_back(u);
			 }
		 }
	 dep[0] = 0; dfs(1, 0, rt);
	 dfncnt=0; leaves.clear();
	 Len = dfs(rt, 0, btm); LCA::init();
	 for (int k = rt; ~k; k = lson[k]) gline.push_back(k);
	 for (int i = 1, tmp; i <= m; ++i){
		 cin >> s[i];
		 L[i].clear();
		 for(int j = 1; j <= s[i]; ++j) {
			 cin >> tmp; L[i].push_back(tmp);
			 }
		 F[i] = dist(L[i].front(), L[i].back());
		 for (unsigned j = 0; j < L[i].size() - 1; ++j)
			 F[i] += dist(L[i][j], L[i][j + 1]);
		 tmp = F[i] >> 1;
		 while (tmp > 1) vis[v[tmp]] = 1, tmp /= v[tmp];
		 }
		 full_dist = dist(leaves.front(), leaves.back());
		 for (unsigned i = 0; i < leaves.size() - 1; ++i)
			 full_dist += dist(leaves[i], leaves[i + 1]);
		 P = -100000;
		 for (int i = 2; i <= prime_cnt; ++i)
			 if (full_dist+2*Len<prime[i] * 2 && !vis[prime[i]]){
			 P = prime[i] * 2; break;
			 }
		 for (int i = 1; i <= m; ++i) {
			 F[i] >>= 1;
			 while (F[i]>1) vis[v[F[i]]] = 0, F[i] /= v[F[i]];
			 }
		 int left=P-full_dist;
		 int fcnt = left / (2 * (Len - 1)); answer = leaves;
		 while (fcnt--) answer.push_back(rt), 
			answer.push_back(btm), left -= 2 * (Len - 1);
		 if (left>>=1) answer.push_back(rt), 
			answer.push_back(gline[left]);
		 for (int qwq: answer) cout << qwq << " ";
		 cout << endl;
		 
}
int main(){
		 prime_init(MAXP);
		 int T; cin >> T;
		 while (T--) solve();
}

学军模拟题

程序题

//将n分为k份非空子集的方案数
#include<bits/stdc++.h>
using namespace std;
int tot=0;
int n,k;
void dfs(int last,int cnt,int ans){
	if(cnt==1)tot++;
	else{
		for(int i=last;i<=ans/cnt;++i)
		{
			dfs(i,cnt-1,ans-i);
		}
	}
}
int main(){
	scanf("%d%d",&n,&k);
	dfs(1,k,n);
	printf("%d\n",tot);
	return 0;
}
//错了一道题说是若k=2,则输出的值为(n-1)/2下取整,当n=6时正确答案为3.故错误,白给了呢
//这里题一道题说是这题可以动归,dp[i][j]表示将i分为k份的方案数,显然每一次操作分为两种,要么分出来新的一个集合,要么就是在原来集合中的任意一个数+1,所以dp[i][j]=dp[i-1][j-1]+dp[i-j][j]
/*纯模拟题
当l=3,m=3时
q[1]=3,q[2]=9,d=1,topa=3,a[1]=1,topa=1,ans[1]=1,topans=1;
q[1]=7,q[2]=9,q[3]=17,a[2]=3,topa=2,ans[2]=3,topans=2;
q[1]=9,q[2]=15,q[3]=17,q[4]=33,a[3]=7,topa=3,ans[3]=7,topans=3,break;
ans[1]=1,ans[2]=3,ans[3]=7,nex[0]=2,m=2;
next[0]=3,m=1;
next[0]=4,m=0;
输出为""

Q:如果输入为14,则当m为()时,第三十九行输出的字典序最大()
A:14	B:18	C:20	D:21
盲猜选A
ANSWER:B
字符串的大小比较,长度不能直接决定大小,字符串的大小是由左边开始最前面的字符决定的。
先把数组a求出来再枚举选项。
*/
#include<bits/stdc++.h>
using namespace std;
priority_queue<int,vector<int>,greater<int> > q;
int a[30005],ans[5000010],topa,topans,nex[5000010];
int main()
{
	int l,m;
	cin>>l>>m;
	memset(ans,0x3f,sizeof(ans));
	q.push(1);
	while(1){
		int x=q.top(),d=0;
		q.pop();
		q.push(2*x+1);
		q.push(4*x+5);
		a[++topa]=x;
		while(x){
			d=d*10+x%10;
			x/=10;
		}
		while(d){
			ans[++topans]=d%10;
			d/=10;
		}
		if(topa>=l)break;
	}
	for(int i=1;i<=topa;++i)cout<<a[i];
	cout<<endl;
	for(int i=0;i<topans;++i)nex[i]=i+1;
	while(m){
		int l=0;
		while(ans[nex[l]]>=ans[nex[nex[l]]])
			l=nex[l];
		nex[l]=nex[nex[l]];
		m--;
	}
	for(int i=0;nex[i];i=nex[i])cout<<ans[nex[i]];
	return 0;
}
/*完善程序,给定一棵n个点的带权树,结点下标从1开始到n,寻找树中找两个点,求最长的异或路径。
构建01trie树,贪心获得最大异或值。本题全队,都是直觉题*/
#include<bits/stdc++.h>
using namespace std;
#define maxn 100005
int trie[maxn+31][2],xo[maxn],ans,rt;
int val[maxn],n,head[maxn],tot;
struct Edge{
	int u,v,w;
}edge[maxn<<1];
void add(int x,int y,int z){
	edge[++tot].u=head[x];
	edge[tot].v=y;
	edge[tot].w=z;
	head[x]=tot;
	edge[++tot].u=head[y];
	edge[tot].v=x;
	edge[tot].w=z;
	head[y]=tot;
}
void build_trie(int x,int rt){
	for(int i=1<<30;i;i>>=1){
		bool c=x&i;
		if(!trie[rt][c])trie[rt][c]=++tot;
		rt=trie[rt][c];
	}
}
int query(int x,int rt){
	int ans=0;
	for(int i=1<<30;i;i>>=1){
		bool c=x&i;
		if(trie[rt][c^1]){
			ans+=i;
			rt=trie[rt][c^1];
		}else rt=trie[rt][c];
	}
	return ans;
}
void dfs(int u,int fa){
	for(int i=head[u];~i;i=edge[i].u){
		if(edge[i].v!=fa){
			xo[edge[i].v]=xo[u]^edge[i].w;
			dfs(edge[i].v,u);
		}
	}
}
int main(){
	memset(head,-1,sizeof head);
	scanf("%d",&n);
	for(int i=1,u,v,w;i<n;++i)
	{
		scanf("%d%d%d",&u,&v,&w);
		add(u,v,w);
	}
	dfs(1,0);
	for(int i=1;i<=n;++i)
		build_trie(xo[i],rt);
	for(int i=1;i<=n;++i)
		ans=max(ans,query(xo[i],rt));
	printf("%d",ans);
	return 0;
}

4.给定平面上n个点,找出其中一对点的距离,使得在这n个点的所有点队中,该距离为所有点队中最小的。

完善程序。

#include<bits/stdc++.h>
using namespace std;
const int maxn=1000001;
const int INF = 2<<20;
int n,temp[maxn];
struct Point{
	double x,y;
}S[maxn];
bool cmp(const Point &a,const Point &b){
	if(a.x==b.x)return a.y<b.y;
	else return a.x<b.x;
}
bool cmps(const int &a,const int &b){
	return S[a].y<S[b].y;
}
double min(double a,double b){
	return a<b?a:b; 
}
double dist(int i,int j){
	double x=(S[i].x-S[j].x)*(S[i].x-S[j].x);
	double y=(S[i].y-S[j].y)*(S[i].y-S[j].y);
	return sqrt(x+y);
}
double merge(int left,int right){
	double d=INF;
	if(left==right)return d;//只有这里错了,left=right意思是没有点队,不能是0,1,-1之类的数
	if(left+1==right)return dist(left,right);
	int mid=left + right >>1;
	double d1=merge(left,mid);
	double d2=merge(mid+1,right);
	d=min(d1,d2);
	int i,j,k=0;
	for(int i=left;i<=right;++i)
		if(fabs(S[mid].x-S[i].x)<d)
			temp[++k]=i;
	sort(temp,temp+k,cmps);
	for(i=0;i<k;++i)
		for(j=i+1;j<k&&S[temp[j]].y-S[temp[i]].y<d;++j)
	{
		double d3=dist(temp[i],temp[j]);
		if(d>d3)d=d3;
	}
	return d;
}
int main(){
	scanf("%d",&n);
	for(int i=0;i<n;++i)
		scanf("%lf%lf",&S[i].x,&S[i].y);
	sort(S,S+n,cmp);
	printf("%.4lf\n",merge(0,n-1));
	return 0;
}
posted @ 2022-09-01 17:30  zyc_xianyu  阅读(1402)  评论(1编辑  收藏  举报