【2023.11.13】NOIP2023模拟试题-33
T1
贪心地找到和最大的组的较大数删除是最优选择,因此开线段树维护全局最大数,并单点更新指定位置的值。
参考代码
展开代码
#include<bits/stdc++.h>
using namespace std;
#define fi(l,r) for(int i=l;i<=r;++i)
#define ff(i,l,r) for(int i=l;i<=r;++i)
#define ll long long
#define ly __int128
#define lp ll
#define lson(x) ((x)<<1)
#define rson(x) (lson(x)|1)
#define Lson(x) tr[lson(x)]
#define Rson(x) tr[rson(x)]
#define mod %P
#define N 500005
struct Info{
int sum,pos;
bool operator < (const Info b)const{return sum<b.sum;}
};
int n,m,tid,a[N],nxt[N],pre[N];
struct node{int l,r,sum,mxi;}tr[N*30];//全局查询+单点修改最大的 a[mxi]+a[nxt[mxi]]
#define valof(x) (a[x]+a[nxt[x]])
void pushup(int x){
if(tr[x].l==tr[x].r)tr[x].mxi=tr[x].l;
else{
if(valof(Lson(x).mxi)>valof(Rson(x).mxi))tr[x].mxi=Lson(x).mxi;
else tr[x].mxi=Rson(x).mxi;
}
return;
}
void build(int x,int l,int r){
tr[x].l=l,tr[x].r=r;
if(l==r){
tr[x].sum=a[l],tr[x].mxi=l;
return;
}
int mid=(l+r)>>1;
build(lson(x),l,mid);
build(rson(x),mid+1,r);
pushup(x);
return;
}
void update(int x,int pos){
if(tr[x].l==tr[x].r){
tr[x].sum=a[pos];
return;
}
if(pos<Rson(x).l)update(lson(x),pos);
else update(rson(x),pos);
pushup(x);
return;
}
int main(){
freopen("necklace.in","r",stdin);
freopen("necklace.out","w",stdout);
scanf("%d %d %d",&tid,&n,&m);
fi(1,n){
nxt[i]=i+1;pre[i]=i-1;
scanf("%d",&a[i]);
}
nxt[n]=1,pre[1]=n;
build(1,1,n);
ff(t,1,n-m){
int x=tr[1].mxi;
if(a[x]<a[nxt[x]])x=nxt[x];//找到和最大的一对里面值最大的一个
nxt[pre[x]]=nxt[x];
pre[nxt[x]]=pre[x];
a[x]=0;//删除这个点
update(1,x);
update(1,pre[x]);
}
printf("%d",valof(tr[1].mxi));
return 0;
}
T2
啊
我们先考虑问题的弱化版:儿子的个数在
如果是这样的话,我们只需要开一个二维 dp
为什么要从子树往根构建而不从根往子树构建呢?
因为考虑所有子树,我们只需要枚举根节点,
而若考虑所有根节点,我们就需要枚举子树。
显然枚举根节点更方便。
接下来我们考虑题目的限制条件。题目更改的条件是
如果第
个节点不为叶子,那么其儿子的最大编号
其实就是从子树往根构建的过程中,除了新建子树以外,还可以添加到子树的非根节点上作为子树的子树。但是我们要从
因此,我们只需要新记录一维需要填补的空缺儿子位置个数
若
显然只能当做新子树或者子树的子树。
因此:
若
显然可能新增左或右
因此:
若
显然可能会新增
参考代码
/*
bug:1.还要钦定这个节点下方待补节点的左右位置
*/
#include<bits/stdc++.h>
using namespace std;
#define fi(l,r) for(int i=l;i<=r;++i)
#define ff(i,l,r) for(int i=l;i<=r;++i)
#define ll long long
#define ly __int128
#define lp ll
#define lson(x) ((x)<<1)
#define rson(x) (lson(x)|1)
#define Lson(x) tr[lson(x)]
#define Rson(x) tr[rson(x)]
#define mod %P
#define P 1000000007
#define N 305
int tid,T,n,ql[N],qr[N];
ll f[N][N][N<<1];
void work(){
memset(f,0,sizeof f);
scanf("%d",&n);
fi(1,n)scanf("%d %d",&ql[i],&qr[i]);
f[0][0][0]=1; //别忘了初始化
fi(0,n-1){
ff(j,0,i){
ff(k,0,i<<1){
if(f[i][j][k]==0)continue;
f[i][j][k]%=P;
if(ql[i+1]==0){
f[i+1][j+1][k]+=f[i][j][k]; //新建根节点
if(k)f[i+1][j][k-1]+=f[i][j][k]*k; //填补k个待定位中的任意一个
}
if(ql[i+1]<=1&&qr[i+1]>=1){
f[i+1][j+1][k+1]+=f[i][j][k]*2; //根节点 + 创建左或右待定子节点 //bug #1 : 同时还要钦定这个节点下的待补节点位置
f[i+1][j][k]+=f[i][j][k]*k*2; //填补待定位 + 创建待定子节点
}
if(qr[i+1]==2){
f[i+1][j+1][k+2]+=f[i][j][k]; //根节点+创建待定子节点
f[i+1][j][k+1]+=f[i][j][k]*k; //填补根节点+创建待定子节点
if(j)f[i+1][j-1][k]+=f[i][j][k]*(j-1)*k*2;//填补待定点 + 引入(所填补的待定点所在链以外)任意一条不保证序号大于自己的链放于左或右儿子 + 创建待定点
f[i+1][j][k+1]+=f[i][j][k]*j*2; //引入任意链 + 创建待定点
}
}
}
}
printf("%lld\n",f[n][1][0]%P); //点统毕,只单链,无待定点
return;
}
int main(){
freopen("tree.in","r",stdin);
freopen("tree.out","w",stdout);
scanf("%d %d",&tid,&T);
while(T-->0)work();
return 0;
}
T3 T4
什么?T3 T4 是我能到达的地方吗?
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现