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.循环列表的优点:
- 没有NULL指针,不必在移动指针的时候判断指针指向的点是否为空
- 从任意节点出发都能遍历整个链表
29.
T(n) = aT(n / b) + f(n)
- 如果f(n) < n^(log(a,b)) ,T(n) = O(n ^ (log(a,b) ) )
- 如果两者相等,则T(n) = O(n ^ (log(a,b) ) * log(n) )
- 如果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都不行。
第五题
第六题
这种手动模拟题就直接摆吧,这道题有五种情况,因为向下翻的次数固定为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;
}