【考试题解】多校A层冲刺NOIP2024模拟赛18
A. 选彩笔(rgb)
题目内容
有
部分分
我不到啊。
正解
思路
观察到题面里鲜明的“最大值最小”,于是考虑二分答案。把每支笔都抽象为三维空间中的点,于是题目变为找一个正方体,包含至少 check
里枚举每一个点,分别把它作为正方体的八个顶点试一试。然后找一个正方体里有多少个点就是经典问题了。由于我们是实时询问,所以
输入:
2 2 1 2 2 2 1 1
输出:
1
锅了的会输出2
。
代码
#include<bits/stdc++.h> using namespace std; #define il inline #define ri register int #define inf 0x3f3f3f3f int a,b,u[100001],v[100001],w[100001],col[262][262][262],pre[262][262][262]; il bool check(int x) { for(ri i=1;i<=a;i++) { ri x1=max(1,u[i]-x),y1=max(1,v[i]-x),z1=max(1,w[i]-x); ri x2=u[i],y2=v[i],z2=w[i]; ri rn=pre[x2][y2][z2]; rn-=pre[x1-1][y2][z2]+pre[x2][y1-1][z2]+pre[x2][y2][z1-1]; rn+=pre[x1-1][y1-1][z2]+pre[x1-1][y2][z1-1]+pre[x2][y1-1][z1-1]; rn-=pre[x1-1][y1-1][z1-1]; if(rn>=b) { return true; } z1=w[i],z2=min(256,w[i]+x); rn=pre[x2][y2][z2]; rn-=pre[x1-1][y2][z2]+pre[x2][y1-1][z2]+pre[x2][y2][z1-1]; rn+=pre[x1-1][y1-1][z2]+pre[x1-1][y2][z1-1]+pre[x2][y1-1][z1-1]; rn-=pre[x1-1][y1-1][z1-1]; if(rn>=b) { return true; } z1=max(1,w[i]-x),z2=w[i]; y1=v[i],y2=min(256,v[i]+x); rn=pre[x2][y2][z2]; rn-=pre[x1-1][y2][z2]+pre[x2][y1-1][z2]+pre[x2][y2][z1-1]; rn+=pre[x1-1][y1-1][z2]+pre[x1-1][y2][z1-1]+pre[x2][y1-1][z1-1]; rn-=pre[x1-1][y1-1][z1-1]; if(rn>=b) { return true; } z1=w[i],z2=min(256,w[i]+x); rn=pre[x2][y2][z2]; rn-=pre[x1-1][y2][z2]+pre[x2][y1-1][z2]+pre[x2][y2][z1-1]; rn+=pre[x1-1][y1-1][z2]+pre[x1-1][y2][z1-1]+pre[x2][y1-1][z1-1]; rn-=pre[x1-1][y1-1][z1-1]; if(rn>=b) { return true; } z1=max(1,w[i]-x),z2=w[i]; y1=max(1,v[i]-x),y2=v[i]; x1=u[i],x2=min(256,u[i]+x); rn=pre[x2][y2][z2]; rn-=pre[x1-1][y2][z2]+pre[x2][y1-1][z2]+pre[x2][y2][z1-1]; rn+=pre[x1-1][y1-1][z2]+pre[x1-1][y2][z1-1]+pre[x2][y1-1][z1-1]; rn-=pre[x1-1][y1-1][z1-1]; if(rn>=b) { return true; } z1=w[i],z2=min(256,w[i]+x); rn=pre[x2][y2][z2]; rn-=pre[x1-1][y2][z2]+pre[x2][y1-1][z2]+pre[x2][y2][z1-1]; rn+=pre[x1-1][y1-1][z2]+pre[x1-1][y2][z1-1]+pre[x2][y1-1][z1-1]; rn-=pre[x1-1][y1-1][z1-1]; if(rn>=b) { return true; } z1=max(1,w[i]-x),z2=w[i]; y1=v[i],y2=min(256,v[i]+x); rn=pre[x2][y2][z2]; rn-=pre[x1-1][y2][z2]+pre[x2][y1-1][z2]+pre[x2][y2][z1-1]; rn+=pre[x1-1][y1-1][z2]+pre[x1-1][y2][z1-1]+pre[x2][y1-1][z1-1]; rn-=pre[x1-1][y1-1][z1-1]; if(rn>=b) { return true; } z1=w[i],z2=min(256,w[i]+x); rn=pre[x2][y2][z2]; rn-=pre[x1-1][y2][z2]+pre[x2][y1-1][z2]+pre[x2][y2][z1-1]; rn+=pre[x1-1][y1-1][z2]+pre[x1-1][y2][z1-1]+pre[x2][y1-1][z1-1]; rn-=pre[x1-1][y1-1][z1-1]; if(rn>=b) { return true; } } return false; } int main() { freopen("rgb.in","r",stdin); freopen("rgb.out","w",stdout); scanf("%d%d",&a,&b); for(ri i=1;i<=a;i++) { scanf("%d%d%d",&u[i],&v[i],&w[i]); u[i]++; v[i]++; w[i]++; col[u[i]][v[i]][w[i]]++; } for(ri i=1;i<=256;i++) { for(ri j=1;j<=256;j++) { for(ri k=1;k<=256;k++) { ri rn=col[i][j][k]; rn+=pre[i-1][j][k]+pre[i][j-1][k]+pre[i][j][k-1]; rn-=pre[i-1][j-1][k]+pre[i-1][j][k-1]+pre[i][j-1][k-1]; rn+=pre[i-1][j-1][k-1]; pre[i][j][k]=rn; } } } ri m=0,n=255; while(n!=m) { ri l=(m+n)>>1; if(check(l)) { n=l; } else { m=l+1; } } printf("%d",m); return 0; }
B. 兵蚁排序(sort)
题目内容
给你两个序列 -1
。多测,
部分分
75pts
暴搜,枚举每次的交换位置,使用哈希来进行去重+剪枝,然后跑的飞快。
点击查看代码
#include<bits/stdc++.h> using namespace std; #define il inline #define ri register int #define inf 0x3f3f3f3f int a,b,c[1001],d[1001],ans; const int base=11491; vector<int>vec; deque<pair<int,int>>que; map<pair<unsigned long long,int>,int>mp; unsigned long long mdd; il unsigned long long _hash(const vector<int> &x) { register unsigned long long rn=0; for(ri i:x) { rn=rn*base+i; } return rn; } bool dfs(int x) { if(x>ans) { return false; } register unsigned long long re=_hash(vec); if(re==mdd) { puts("0"); printf("%d\n",x-1); while(!que.empty()) { printf("%d %d\n",que.front().first,que.front().second); que.pop_front(); } return true; } if(mp[{re,a}]&&mp[{re,a}]<=x) { return false; } mp[{re,a}]=x; vector<int>now(vec); for(ri i=0;i<vec.size()-1;i++) { for(ri j=i+1;j<vec.size();j++) { sort(vec.begin()+i,vec.begin()+j+1); que.push_back({i+1,j+1}); if(dfs(x+1)) { return true; } que.pop_back(); vec=now; } } return false; } int main() { freopen("sort.in","r",stdin); freopen("sort.out","w",stdout); scanf("%d",&a); while(a--) { scanf("%d",&b); vec.clear(); for(ri i=1;i<=b;i++) { scanf("%d",&c[i]); vec.push_back(c[i]); } mdd=0; for(ri i=1;i<=b;i++) { scanf("%d",&d[i]); mdd=mdd*base+d[i]; } ans=b*b; if(!dfs(1)) { puts("-1"); } } return 0; }
正解
思路
由于题目保证
代码
#include<bits/stdc++.h> using namespace std; #define il inline #define ri register int #define inf 0x3f3f3f3f int a,b,c[1001],d[1001],ans,to[1001]; queue<int>que[1001]; queue<pair<int,int>>ask; il bool bubble() { for(ri i=1;i<b;i++) { for(ri j=1;j<b;j++) { if(to[j]>to[j+1]) { if(c[j]<c[j+1]) { while(!ask.empty()) { ask.pop(); } return false; } else { swap(c[j],c[j+1]); swap(to[j],to[j+1]); ask.push({j,j+1}); } } } } return true; } int main() { freopen("sort.in","r",stdin); freopen("sort.out","w",stdout); scanf("%d",&a); while(a--) { scanf("%d",&b); for(ri i=1;i<=b;i++) { scanf("%d",&c[i]); que[c[i]].push(i); } for(ri i=1;i<=b;i++) { scanf("%d",&d[i]); to[que[d[i]].front()]=i; que[d[i]].pop(); } ans=bubble(); if(ans) { puts("0"); printf("%d\n",ask.size()); while(!ask.empty()) { printf("%d %d\n",ask.front().first,ask.front().second); ask.pop(); } } else { puts("-1"); } } return 0; }
C. 人口局DBA(dba)
题目内容
给你一个
部分分
60pts
数位DP,但是赛时打锅了。
正解
思路
推式子。设
我们先看
然后反演求
类比数位DP,设第
现在重点在于简化后面的那个 充分发扬人类智慧,把这个玩意儿放杨辉三角上,发现这个东西是类似
我们要求的是红色的
然后直接求就可以了。注意特判组合数为
代码
#include<bits/stdc++.h> using namespace std; #define il inline #define ri register int #define inf 0x3f3f3f3f int a,b,c[2002]; const int mod=1e9+7; long long jc[4000004],ny[4000004],sm,ans; il long long qpow(long long x,long long y) { register long long rn=1; while(y) { if(y&1) { rn=(rn*x)%mod; } x=(x*x)%mod; y>>=1; } return rn; } il long long C(int x,int y) { if(x<y) { return 0; } return (((jc[x]*ny[x-y])%mod)*ny[y])%mod; } int main() { freopen("dba.in","r",stdin); freopen("dba.out","w",stdout); scanf("%d%d",&a,&b); for(ri i=b;i>=1;i--) { scanf("%d",&c[i]); sm+=c[i]; } jc[0]=ny[0]=1; for(ri i=1;i<=a*b;i++) { jc[i]=(jc[i-1]*i)%mod; ny[i]=qpow(jc[i],mod-2); } for(ri i=b;i>=1;i--) { register long long rn=0; for(ri j=0;j<i;j++) { ri op=(j&1)?-1:1; register long long k=(C(i-1,j)*((C(sm-a*j+i-1,i-1)-C(sm-c[i]-a*j+i-1,i-1)+mod)%mod))%mod; rn=(rn+op*k)%mod; rn=(rn+mod)%mod; } ans=(ans+rn)%mod; sm-=c[i]; } printf("%lld",ans); return 0; }
D. 银行的源起(banking)
不会。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】