第一题仓库规划
西西艾弗岛上共有 n 个仓库,依次编号为 1⋯n。每个仓库均有一个 m 维向量的位置编码,用来表示仓库间的物流运转关系。
具体来说,每个仓库 i 均可能有一个上级仓库 j,满足:仓库 j 位置编码的每一维均大于仓库i 位置编码的对应元素。比如编码为 (1,1,1) 的仓库可以成为 (0,0,0) 的上级,但不能成为 (0,1,0) 的上级。如果有多个仓库均满足该要求,则选取其中编号最小的仓库作为仓库 i 的上级仓库;如果没有仓库满足条件,则说明仓库 i 是一个物流中心,没有上级仓库。
现给定 n 个仓库的位置编码,试计算每个仓库的上级仓库编号。
一个简单的模拟题
#include<cstdio>
#include<cstdlib>
#include<iostream>
using namespace std;
int ma[1001][11];
int main()
{
int n,m;
cin>>n>>m;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
cin>>ma[i][j];
}
for(int i=1;i<=n;i++)
{
bool pd2=false;
for(int j=1;j<=n;j++)
{
bool pd=true;
if(i==j) continue;
for(int k=1;k<=m;k++)
{
if(ma[j][k]>ma[i][k])
{
continue;
}
else
{
pd=false;
break;
}
}
if(pd)
{
pd2=true;
cout<<j<<endl;
break;
}
}
if(!pd2)
{
cout<<0<<endl;
}
}
return 0;
}
第二题因子化简
小 P 同学在学习了素数的概念后得知,任意的正整数 都可以唯一地表示为若干素因子相乘的形式。如果正整数 n 有 m 个不同的素数因子 ,则可以表示为:
小 P 认为,每个素因子对应的指数 反映了该素因子对于 的重要程度。现设定一个阈值 ,如果某个素因子 对应的指数 小于 ,则认为该素因子不重要,可以将 项从 中除去;反之则将 项保留。最终剩余项的乘积就是 简化后的值,如果没有剩余项则认为简化后的值等于 1。
试编写程序处理 q 个查询:
- 每个查询包含两个正整数 n 和 k,要求计算按上述方法将 n 简化后的值。
利用线性筛筛出所有素数后,一个一个遍历去尝试,即可得到答案
#include<cstdio>
#include<cstdlib>
#include<iostream>
using namespace std;
bool numlist[100000001];
int prime[2000001], tot;
void work(int n){
for(int i=2; i*i<=n; i++){
if(numlist[i]==false){
prime[++tot] = i ;
for(int j=i; i*j<=n; j++)
numlist[i*j] = true;
}
}
return;
}
int main()
{
int q,t2;
long long t1;
work(1000001);
cin>>q;
for(int i=1;i<=q;i++)
{
cin>>t1>>t2;
long long ans=1,temp=0,jl=1;
for(int t=1;t<=tot;t++)
{
temp=0,jl=1;
while(t1%prime[t]==0)
{
t1=t1/prime[t];
jl=jl*prime[t];
temp++;
}
if(temp>=t2)
ans=ans*jl;
}
cout<<ans<<endl;
}
return 0;
}
第三题树上搜索
西西艾弗岛大数据中心为了收集用于模型训练的数据,推出了一项自愿数据贡献的系统。岛上的居民可以登录该系统,回答系统提出的问题,从而为大数据中心提供数据。为了保证数据的质量,系统会评估回答的正确性,如果回答正确,系统会给予一定的奖励。
近期,大数据中心需要收集一批关于名词分类的数据。系统中会预先设置若干个名词类别,这些名词类别存在一定的层次关系。例如,“动物”是“生物”的次级类别,“鱼类”是“动物”的次级类别,“鸟类”是“动物”的次级类别,“鱼类”和“鸟类”是“动物”下的邻居类别。这些名词类别可以被按树形组织起来,即除了根类别外,每个类别都有且仅有一个上级类别。
并且所有的名词都可以被归类到某个类别中,即每个名词都有且仅有一个类别与其对应。一个类别的后代类别的定义是:若该类别没有次级类别,则该类别没有后代类别;否则该类别的后代类别为该类别的所有次级类别,以及其所有次级类别的后代类别。
下图示意性地说明了标有星号的类别的次级类别和后代类别。
次级类别与后代类别
系统向用户提出问题的形式是:某名词是否属于某类别,而用户可以选择“是”或“否”来回答问题。该问题的含义是:某名词是否可以被归类到某类别或其后代类别中。
例如,要确定名词“鳕鱼”的类别,系统会向用户提出“鳕鱼是否属于动物”,当用户选择“是”时,系统会进一步询问“鳕鱼是否属于鱼类”,当用户选择“是”时,即可确定“鳕鱼”可以被归类到“鱼类”这一类别。
此外,如果没有更具体的分类,某一名词也可以被归类到非叶子结点的类别中。例如,要确定“猫”的类别,系统可以向用户提出“猫是否属于动物”,当用户选择“是”时,系统会进一步分别询问“猫”是否属于“鱼类”和“鸟类”,当两个问题收到了否定的答案后,系统会确定“猫”的类别是“动物”。
大数据中心根据此前的经验,已经知道了一个名词属于各个类别的可能性大小。为了用尽量少的问题确定某一名词的类别,大数据中心希望小 C 来设计一个方法,以减少系统向用户提出的问题的数量。
问题描述
小 C 观察了事先收集到的数据,并加以统计,得到了一个名词属于各个类别的可能性大小的信息。具体而言,每个类别都可以赋予一个被称为权重的值,值越大,说明一个名词属于该类别的可能性越大。由于每次向用户的询问可以获得两种回答,小 C 联想到了二分策略。他设计的策略如下:
- 对于每一个类别,统计它和其全部后代类别的权重之和,同时统计其余全部类别的权重之和,并求二者差值的绝对值,计为 ;
- 选择 最小的类别,如果有多个,则选取编号最小的那一个,向用户询问名词是否属于该类别;
- 如果用户回答“是”,则仅保留该类别及其后代类别,否则仅保留其余类别;
- 重复步骤 1,直到只剩下一个类别,此时即可确定名词的类别。
小 C 请你帮忙编写一个程序,来测试这个策略的有效性。你的程序首先读取到所有的类别及其上级次级关系,以及每个类别的权重。你的程序需要测试对于被归类到给定类别的名词,按照上述策略提问,向用户提出的所有问题。
一个大模拟题,对于单个查询,遍历所有存活的节点,遍历出最小的节点,选择其子树,如果目标节点在子树里面则只保留这颗子树,否则,去除这颗子树,更新信息。
#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<cmath>
using namespace std;
int n,m;
long long stototval,val[2001],sonval[2001],totval,stosonval[2001];
bool live[2001],livefind[2001];
long long lives,stolives;
int head[2001],tot=1;
struct node
{
int to,next;
}ma[10000001];
void add(int a,int b)
{
ma[tot].to=b;
ma[tot].next=head[a];
head[a]=tot++;
}
long long firstdfs(int now)
{
long long sum=0;
stolives++;
for(int i=head[now];i;i=ma[i].next)
{
int y=ma[i].to;
sum+=firstdfs(y);
}
sonval[now]=sum+val[now];
return sonval[now];
}
bool find(int now,int mb)
{
bool sum=0;
if(now==mb) return 1;
for(int i=head[now];i;i=ma[i].next)
{
int y=ma[i].to;
if(live[y])
sum+=find(y,mb);
}
return sum;
}
long long dfsup(int now)
{
long long temp=0;
livefind[now]=true;
for(int i=head[now];i;i=ma[i].next)
{int y=ma[i].to;
if(live[y])
temp+=dfsup(y);
}
temp+=val[now];
sonval[now]=temp;
return temp;
}
int main()
{
cin>>n>>m;
for(int i=1;i<=n;i++)
{
cin>>val[i];
}
for(int i=2;i<=n;i++)
{
int fa;
cin>>fa;
add(fa,i);
}
firstdfs(1);
for(int i=1;i<=n;i++)
stosonval[i]=sonval[i];
stototval=sonval[1];
for(int opt=1;opt<=m;opt++)
{
int t1;
cin>>t1;
lives=stolives;
int root=1;
root=1;
totval=stototval;
for(int i=1;i<=n;i++)
{
sonval[i]=stosonval[i];
live[i]=true;
livefind[i]=false;
}
while(lives>=2)
{
totval=0;
for(int i=1;i<=n;i++)
if(live[i])
totval+=val[i];
long long maxn=9999999999999,mb=-1;
for(int i=1;i<=n;i++)
{
if(live[i])
if(abs(2*sonval[i]-totval)<maxn)
{
maxn=abs(2*sonval[i]-totval);
mb=i;
}
}
cout<<mb<<" ";
if(find(mb,t1))
{
lives=0;
root=mb;
dfsup(mb);
for(int i=1;i<=n;i++)
{
if(livefind[i])
{
live[i]=true;
lives++;
}
else
{
live[i]=false;
}
livefind[i]=false;
}
}
else
{
live[mb]=false;
lives=0;
dfsup(root);
for(int i=1;i<=n;i++)
{
if(livefind[i])
{
live[i]=true;lives++;
}
else
{
live[i]=false;
}
livefind[i]=false;
}
}
}
cout<<endl;
}
return 0;
}