当前位置: 首页 > news >正文

sm2025 模拟赛24 (2025.10.20)

文章目录

  • T1 超级集合
  • T2 宝可梦
  • T3 城市地铁
  • T4 寿司晚宴

T1 超级集合

link
思路
由于删数的实际作用是减小剩下数的排名,所以最后答案排名为 1 1 1
考虑时光倒流。在第 k k k 轮结束后,答案排名为 x = 1 x=1 x=1。考虑第 k − 1 k-1 k1 轮答案的排名 x ′ x' x 。找到最大的 i i i 满足 a i + 1 ≤ x + i a_i+1\le x+i ai+1x+i ,即 a i − i + 1 ≤ x a_i-i+1 \le x aii+1x ,此时 x ′ ← x + i x' \leftarrow x+i xx+i 。这样一轮轮枚举的复杂度为 O ( k ) O(k) O(k) 。发现随着 x x x 的增大, i i i 也会增大。那么从小到大枚举 i i i ,计算出有多少轮的 x x x 的决策点在 i i i ,复杂度 O ( n ) O(n) O(n)

反思
好像之前模拟赛2出过类似思路的题?
所以对于这种删数的是不是可以考虑倒着做然后加数。
虽然但是找规律也有 75pts .

代码

#pragma GCC optimize(3)
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=1e5+5;
ll a[maxn];
int main(){freopen("superset.in","r",stdin);freopen("superset.out","w",stdout);int id,t; cin>>id>>t;while(t--){ll n,k; cin>>n>>k;for(int i=1;i<=n;i++)cin>>a[i];if(a[1]>1){cout<<"1\n";continue;}ll x=1;for(int i=1;i<n;i++){ll tmp=(a[i+1]-x-1)/i;if(tmp>k){x+=k*i;break;}x+=tmp*i; k-=tmp;}cout<<x+n*k<<"\n";}return 0;
}

T2 宝可梦

link
思路
首先每只怪物的每种属性只会被改一次。考虑建图,直接暴力建边为 O ( n 2 m ) O(n^2m) O(n2m) 。考虑优化建图。
首先带着点权 c i c_i ci 操作不方便,将一个点拆成入点和出点。然后由于每个属性值只会从小变化到大,所以对于每种属性,将怪物排序后用一条链连起来即可,边权为相邻两值的差。总共会连 O ( 4 n m ) O(4nm) O(4nm) 条边。跑一次最短路即可。

代码

#pragma GCC optimize(3)
#include<bits/stdc++.h>
#define ll long long
#define pir pair<ll,int>
using namespace std;
const int maxn=4e5+5,INF=1e18;int idx,head[maxn];
struct EDGE{ int v,next; ll w; }e[maxn*2];
void Insert(int u,int v,ll w){e[++idx]={v,head[u],w};head[u]=idx;
}int n,m;
ll dis[maxn];
priority_queue<pir,vector<pir>,greater<pir> >q; 
void Dij(){for(int i=1;i<=n*m+n;i++){dis[i]=INF;}while(!q.empty()) q.pop();dis[n*m+1]=0; q.push({0,n*m+1});while(!q.empty()){int x=q.top().second; ll y=q.top().first; q.pop();if(dis[x]<y) continue;for(int i=head[x];i;i=e[i].next){int v=e[i].v;if(dis[v]>dis[x]+e[i].w){dis[v]=dis[x]+e[i].w;q.push({dis[v],v});}}}
}struct NODE{ll w; int id; bool operator < (const NODE a)const{return a.w>w;}
};
vector<NODE>a[maxn];
int main(){freopen("pokemon.in","r",stdin);freopen("pokemon.out","w",stdout);int id,t; scanf("%d%d",&id,&t);while(t--){scanf("%d%d",&n,&m);for(int i=1,x;i<=n;i++){scanf("%d",&x);for(int j=1;j<=m;j++)Insert((i-1)*m+j,n*m+i,x),Insert(n*m+i,(i-1)*m+j,0);}for(int i=1;i<=n;i++)for(int j=1,x;j<=m;j++){scanf("%d",&x);a[j].push_back({x,i});}for(int i=1;i<=m;i++){sort(a[i].begin(),a[i].end());for(int j=1;j<n;j++){Insert((a[i][j].id-1)*m+i,(a[i][j-1].id-1)*m+i,a[i][j].w-a[i][j-1].w),Insert((a[i][j-1].id-1)*m+i,(a[i][j].id-1)*m+i,0);}}Dij();printf("%lld\n",dis[n*m+n]);for(int i=1;i<=m;i++)a[i].clear();memset(head,0,sizeof(head));idx=0;}return 0;
}

T3 城市地铁

link
思路
首先我们希望对于每个询问 ( x , y ) (x,y) (x,y) ,让 x , y x,y x,y 都跳到他们的 lca ,此时的换乘数量之和 − - 跳到 lca 时最后是否乘到同一个地铁就是答案。发现一步步跳很慢,考虑倍增。记 f i , j f_{i,j} fi,j 表示从 i i i 号点换乘 2 j 2^j 2j 次能跳到的最高的点。
实际上判断 x , y x,y x,y 跳到 lca 时最后是否乘到同一个地铁可以将询问离线下来,即在 x , y x,y x,y 都跳到 lca 的下一层时要判断是否有一条地铁能从 x ′ x' x 的子树出发到达 y ′ y' y 的子树,这可以将子树通过 d f n dfn dfn 转化为一段连续的区间,类似二位数点判断即可。

代码

#include<bits/stdc++.h>
using namespace std;
const int maxn=2e5+5;int idx,head[maxn];
struct EDGE{ int v,next; }e[maxn*2];
void Insert(int u,int v){e[++idx]={v,head[u]};head[u]=idx;
}int dep[maxn],fatr[maxn][23],dfn[maxn],ed[maxn],tim;
void Dfs(int x,int fa){dep[x]=dep[fa]+1; fatr[x][0]=fa; dfn[x]=++tim;for(int i=0;i<20;i++)fatr[x][i+1]=fatr[fatr[x][i]][i];for(int i=head[x];i;i=e[i].next){int v=e[i].v;if(v!=fa) Dfs(v,x);}ed[x]=tim;
}int Get_lca(int x,int y){if(dep[x]<dep[y]) swap(x,y);for(int i=20;i>=0;i--)if(dep[fatr[x][i]]>=dep[y]) x=fatr[x][i];if(x==y) return x;for(int i=20;i>=0;i--)if(fatr[x][i]!=fatr[y][i]) x=fatr[x][i],y=fatr[y][i];return fatr[x][0];
}int f[maxn][23];
vector<int>pos[maxn];
int Dfs2(int x,int fa){int mi=x;for(auto i:pos[x])if(dep[i]<dep[mi]) mi=i;for(int i=head[x];i;i=e[i].next){int v=e[i].v;if(v!=fa){int tmp=Dfs2(v,x);if(dep[tmp]<dep[mi]) mi=tmp;}}return f[x][0]=mi;
}void Dfs3(int x,int fa){for(int i=0;i<20;i++)f[x][i+1]=f[f[x][i]][i];for(int i=head[x];i;i=e[i].next){int v=e[i].v;if(v!=fa) Dfs3(v,x);}
}int Jump_(int &x,int d){int s=0;for(int i=20;i>=0;i--)if(dep[f[x][i]]>d) x=f[x][i],s+=(1<<i);return s;
}int n,tree[maxn];
void Add(int x){while(x<=n) tree[x]++,x+=x&(-x);
}
int Ask(int x){int s=0;while(x) s+=tree[x],x-=x&(-x);return s;
}int ans[maxn],ok[maxn];
struct SUY{ int x,y; }sw[maxn];
struct QUE{ int x,ql,qr,id,op; }ct[maxn*2];
int main(){freopen("metro.in","r",stdin);freopen("metro.out","w",stdout);int id; cin>>id>>n;for(int i=1;i<n;i++){int x,y; cin>>x>>y;Insert(x,y),Insert(y,x);}Dfs(1,0);int m; cin>>m;for(int i=1;i<=m;i++){int x,y; cin>>x>>y;int lca=Get_lca(x,y);pos[x].push_back(lca); pos[y].push_back(lca);if(dfn[x]>dfn[y]) swap(x,y);sw[i]={dfn[x],dfn[y]};}Dfs2(1,0),Dfs3(1,0);int q; cin>>q; int tot=0;for(int i=1;i<=q;i++){int x,y; cin>>x>>y;if(x==y){ ans[i]=0; continue; }int lca=Get_lca(x,y); if(dep[x]>dep[y]) swap(x,y);if(x==lca){ans[i]=Jump_(y,dep[lca]);if(dep[f[y][0]]<=dep[lca]) ans[i]++;else ans[i]=-1;}else{ans[i]=Jump_(x,dep[lca])+Jump_(y,dep[lca]);if(dep[f[x][0]]<=dep[lca]&&dep[f[y][0]]<=dep[lca]){ans[i]+=2;if(dfn[x]>dfn[y]) swap(x,y);ct[++tot]={dfn[x]-1,dfn[y],ed[y],i,-1};ct[++tot]={ed[x],dfn[y],ed[y],i,1};}else ans[i]=-1;}}sort(sw+1,sw+m+1,[](SUY a,SUY b){ return a.x<b.x; });sort(ct+1,ct+tot+1,[](QUE a,QUE b){ return a.x<b.x; });for(int i=1,j=1;i<=tot;i++){while(j<=m&&sw[j].x<=ct[i].x) Add(sw[j++].y);ok[ct[i].id]+=ct[i].op*(Ask(ct[i].qr)-Ask(ct[i].ql-1));}for(int i=1;i<=q;i++){if(ans[i]==-1) cout<<"-1\n";else{if(ok[i]) ans[i]--;cout<<ans[i]<<"\n";}}return 0;
}

T4 寿司晚宴

link
思路
首先如果确定了排列 A , B , C A,B,C A,B,C ,那么每个人吃的顺序是固定的。到某一轮三人分别选择 x , y , z x,y,z x,y,z 的寿司时,此时前面的寿司已经被选完,那么如果 C 有贡献当且仅当 x , y x,y x,y 都在 z z z 的后面。所以从后往前推,如果已经确定 c c c 吃了哪些寿司,考虑将不是 c 吃的那部分寿司插入 c 吃的排列中,那么对应的排列数为 ∏ i = 1 n 3 ( 3 × i − 1 ) ( 3 × i − 2 ) \prod\limits_{i=1}^{\frac{n}{3}}(3\times i-1)(3\times i-2) i=13n(3×i1)(3×i2)
那么现在只需要知道 c c c 吃了哪些寿司即可。考虑计数的限制条件。

  • a,b,c 各自吃的寿司不会有重复;
  • a 吃了的寿司不会被 b,c 选择,b,c 同理。
  • a,b,c 每一轮都要吃;

所以说到第 t t t 轮,c 能选择的数为 3 × t − ∣ { a i 1 , a i 2 , … , a i t } ∪ { b i 1 , b i 2 , … , b i t } ∣ 3\times t-|\{a_{i_1},a_{i_2},\dots,a_{i_t}\}\cup \{b_{i_1},b_{i_2},\dots ,b_{i_t}\}| 3×t{ai1,ai2,,ait}{bi1,bi2,,bit} 。设 f t , i , j f_{t,i,j} ft,i,j 表示考虑到第 t t t 轮,a 吃了 i i ib 吃了 j j jc 的选择数。转移为: f t , i , j = ∑ i ′ < i , j ′ < j f t − 1 , i ′ , j ′ × ( 3 × t − ∣ { a i 1 , a i 2 , … , a i t } ∪ { b i 1 , b i 2 , … , b i t } ∣ ) f_{t,i,j}=\sum\limits_{i'\lt i,j'\lt j} f_{t-1,i',j'}\times (3\times t-|\{a_{i_1},a_{i_2},\dots,a_{i_t}\}\cup \{b_{i_1},b_{i_2},\dots ,b_{i_t}\}|) ft,i,j=i<i,j<jft1,i,j×(3×t{ai1,ai2,,ait}{bi1,bi2,,bit})
前缀和优化一下,复杂度为 O ( n 3 ) O(n^3) O(n3)

反思

计数的通常方式是列出限制条件,再根据限制条件解决 。

代码

#pragma GCC optimize(3)
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=405,maxt=140,mod=1e9+7;
int a[maxn],b[maxn];
ll f[maxt][maxn][maxn],g[maxn][maxn];
bool vis[maxn],oka[maxn][maxn],okb[maxn][maxn];
int main(){freopen("sushi.in","r",stdin);freopen("sushi.out","w",stdout);int id,t; cin>>id>>t;while(t--){int n; cin>>n;for(int i=1;i<=n;i++)cin>>a[i];for(int i=1;i<=n;i++)cin>>b[i];for(int i=1;i<=n;i++){vis[a[i]]=1;g[i][0]=i;for(int j=1;j<=n;j++){g[i][j]=g[i][j-1];if(!vis[b[j]]) g[i][j]++;}}for(int i=1;i<=n;i++)for(int j=1;j<=i;j++)okb[i][b[j]]=1,oka[i][a[j]]=1;for(int i=0;i<=n;i++)for(int j=0;j<=n;j++)f[0][i][j]=1;for(int i=1;i<=n/3;i++)for(int j=1;j<=i*3;j++)for(int k=1;k<=i*3;k++){if(!okb[k][a[j]]&&!oka[j][b[k]]) (f[i][j][k]+=f[i-1][j-1][k-1]*(3*i-g[j][k])%mod)%=mod;(f[i][j][k]+=((f[i][j-1][k]+f[i][j][k-1])%mod-f[i][j-1][k-1]+mod)%mod)%=mod;}ll ans=f[n/3][n][n];for(int i=1;i<=n/3;i++)(ans*=(3*i-1)%mod*(3*i-2)%mod)%=mod;cout<<ans<<"\n";for(int i=1;i<=n/3;i++)for(int j=1;j<=n;j++){vis[j]=0;for(int k=1;k<=n;k++)f[i][j][k]=0,g[j][k]=0,oka[j][k]=okb[j][k]=0;}}return 0;
}
http://www.dtcms.com/a/508092.html

相关文章:

  • 【完整源码+数据集+部署教程】【后勤&运输集装箱】集装箱表面腐蚀检测系统源码&数据集全套:改进yolo11-swintransformer
  • 20.哈希
  • 公司网站表达的内容wordpress怎么上传高清图片大小
  • 慧聪网网站建设策略用腾讯云做淘宝客网站视频
  • XSS_and_Mysql_file靶场攻略
  • 引领交易革命:一站式去中心化交易所Swap开发一体化方案
  • 多样化的网站建设公司张雪峰谈工业设计专业
  • Houdini UV节点uvunwrap 和 uvproject和uvtexture 有什么区别
  • Vue3 条件语句详解
  • CAN总线: 位同步,接收方数据采样
  • 解决host.robots.ox.ac.uk打不开无法下载voc2007和voc2012问题
  • SQL入门:正则表达式-高效文本匹配全攻略
  • 个体制作网站设计高端创意网站建设
  • 舟山网站建设代理如何创立个人网站
  • Linux 服务器运维之 Nginx 案例化培训教程
  • 企业级SQL审核工具PawSQL介绍(1) - 六大核心能力
  • 黄山家居网站建设怎么样晋城网站seo
  • 网站的主域名提升学历图片素材
  • 佛山规划建设局网站wap网站如何建设
  • IP和端口号
  • 算法题——动态规划
  • asp网站模板如何修改有些人做网站不用钱的,对吗?
  • 网站关键词用热门的还是冷门画册设计免费模板
  • Java的代码块介绍与快速入门
  • wordpress wordpress获取当前页面的父类id外贸seo推广公司
  • 企业建站 炫酷模板网站上线方案
  • 学习哈希表的基本结构
  • 学习Python 04
  • AJAX的学习
  • Python爬虫实战:淘宝模拟人工搜索关键词采集商品列表