2024.8.1 模拟赛13
1.2024.7.18模拟赛12.2024.7.19模拟赛23.2024.7.20模拟赛34.2024.7.21模拟赛45.2024.7.22模拟赛56.2024.7.23 模拟赛67.2024.7.25模拟赛78.2024.7.26模拟赛89.2024.7.27模拟赛910.2024.7.28 模拟赛1011.2024.7.29模拟赛1112.2024.7.31模拟赛12
13.2024.8.1 模拟赛13
14.2024.8.6 模拟赛 1415.2024.8.7 模拟赛 1516.2024.8.8模拟赛1617.2024.8.10模拟赛1718.2024.8.18 模拟赛 2219.2024.8.19 模拟赛 2420.小集训21.2024.9.23 模拟赛 CSP 322.2024.9.24 模拟赛 CSP423.2024.9.25 模拟赛 多校24.2024.9.27 模拟赛 CSP525.2024.9.28 模拟赛 CSP626.2024.9.30 模拟赛 CSP727.2024.10.7 模拟赛 多校328.2024.?.?? 模拟赛 ???模拟赛
最崩的一场,断断续续补题解。
“小孩召开法” 专场。
T1 Shiritori
很裸的一道博弈论,不用考虑 SG 函数这种高级东西,从最简单的定义出发。
把所有字符串收尾相连建边,会得到一张 DAG,然后就是经典有向图问题。
如果最后没有后继节点,那必赢,如果所有子节点都是必赢的状态,那必输,否则必赢。
注意状压记忆化。
code
#include<bits/stdc++.h>
using namespace std;
#define scan __builtin_scanf
#define print __builtin_printf
#define LL long long
const int N = 17;
int n,ans;
int f[1<<16][17],len[N];
char s[N][15];
bool dfs(int i,int h)
{
if(~f[i][h]) return f[i][h];
for(int j=1;j<=n;j++)
{
if((1<<j-1)&i) continue;
if(s[j][1]==s[h][len[h]])
{
if(!dfs(i|(1<<j-1),j)) return f[i][h]=1;
}
}
return f[i][h]=0;
}
int main()
{
// freopen("in.in","r",stdin);
// freopen("out.out","w",stdout);
memset(f,-1,sizeof(f));
scan("%d",&n);
for(int i=1;i<=n;i++) scan("%s",(s[i]+1)),len[i]=strlen(s[i]+1);
for(int i=1;i<=n;i++)
{
if(!dfs(1<<i-1,i)) return print("First\n"),0;
}
print("Second\n");
return 0;
}
T2 Nauuo and Binary Tree
比较好想的是处理深度,花费
然后按深度一层一层填树,所以填到第
如果我们查询要填的这个点和一个已知点的距离,可以得到 lca 的深度
如何通过 lca 去找当前点的位置呢?为了将操作次数压在
我们记录每条重链的链尾(深度最深的),然后查询链尾和当前点的距离得到 lca 的深度。
lca 一定就在这条重链上,所以暴跳下去。如果找到 lca 的父亲还不是当前节点的父亲,那就跳一次轻儿子,再重复上述过程。
因为重链只会有
code
#include<bits/stdc++.h>
using namespace std;
#define scan __builtin_scanf
#define print __builtin_printf
#define LL unsigned int
const int N = 3005;
int n,fa[N],son[N][2],dep[N],sz[N],ta[N];
vector<int> v[N];
inline void ask(int x,int y)
{
cout<<"? "<<x<<" "<<y<<endl;
}
inline void add(int f,int u)
{
fa[u]=f;
son[f][0]?son[f][1]=u:son[f][0]=u;
}
void dfs(int u)
{
sz[u]=1; ta[u]=u;
if(son[u][0])
{
dfs(son[u][0]);
sz[u]+=sz[son[u][0]];
}
if(son[u][1])
{
dfs(son[u][1]);
sz[u]+=sz[son[u][1]];
if(sz[son[u][1]]>sz[son[u][0]]) swap(son[u][0],son[u][1]);
}
if(son[u][0]) ta[u]=ta[son[u][0]];
}
void work(int u)
{
int v=1,dis;
while(dep[v]!=dep[u]-1)
{
ask(u,ta[v]);
scan("%d",&dis);
dis=(dep[u]+dep[ta[v]]-dis)>>1;
while(dep[v]<dis) v=son[v][0];
if(dep[v]==dep[u]-1) break;
v=son[v][1];
}
add(v,u);
}
int main()
{
// freopen("in.in","r",stdin);
// freopen("out.out","w",stdout);
scan("%d",&n);
for(int i=2;i<=n;i++)
{
ask(1,i);
scan("%d",&dep[i]);
v[dep[i]].push_back(i);
}
for(int i=1;i<=n;i++)
{
dfs(1);
for(int j:v[i]) work(j);
}
cout<<"!";
for(int i=2;i<=n;i++) cout<<" "<<fa[i];
cout<<endl;
return 0;
}
T3 好吃的题目
猫树分治板子(学完整体二分可能理解更深)。
“猫树”长这个样子
猫树分治通常可以解决具有以下特征的问题:
-
静态序列,多组查询。
-
对于查询的区间我们可以从中间分成两部分然后合并。也就是区间之间可以结合。
假设查询区间为
既然答案可以由两部分合成,那我们就整体二分,从
注意背包数组每次都要初始化,表示起点为
code
#include<bits/stdc++.h>
using namespace std;
#define mx(x,y) (x>y?x:y)
const int N = 4e4+5,M = 2e5+5;
int n,m;
int h[N],cnt;
int f[N][201],w[N],ans[M];
struct Q {int l,r,t,id;} q[M],q1[M],q2[M];
void work(int l,int r,int ql,int qr)
{
if(ql>qr) return;
if(l==r) return ;
int mid=l+r>>1;
for(int i=0;i<=200;i++) f[mid][i]=0;
for(int i=mid+1;i<=r;i++)
{
for(int j=0;j<=200;j++) f[i][j]=f[i-1][j];
for(int j=h[i];j<=200;j++) f[i][j]=max(f[i][j],f[i-1][j-h[i]]+w[i]);
}
for(int i=0;i<h[mid];i++) f[mid][i]=0; for(int i=h[mid];i<=200;i++) f[mid][i]=w[mid];
for(int i=mid-1;i>=l;i--)
{
for(int j=0;j<=200;j++) f[i][j]=f[i+1][j];
for(int j=h[i];j<=200;j++) f[i][j]=max(f[i][j],f[i+1][j-h[i]]+w[i]);
}
int c1=0,c2=0;
for(int i=ql;i<=qr;i++)
{
if(q[i].r<=mid) q1[++c1]=q[i];
else if(q[i].l>mid) q2[++c2]=q[i];
else
{
int tmp=0;
for(int j=0;j<=q[i].t;j++) tmp=mx(tmp,f[q[i].l][j]+f[q[i].r][q[i].t-j]);
ans[q[i].id]=tmp;
}
}
for(int i=ql;i<=ql+c1-1;i++) q[i]=q1[i-ql+1];
for(int i=ql+c1;i<=ql+c1+c2-1;i++) q[i]=q2[i-c1-ql+1];
work(l,mid,ql,ql+c1-1);work(mid+1,r,ql+c1,ql+c1+c2-1);
}
int main()
{
// freopen("in.in","r",stdin);
// freopen("out.out","w",stdout);
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) scanf("%d",&h[i]);
for(int i=1;i<=n;i++) scanf("%d",&w[i]);
for(int i=1;i<=m;i++)
{
int l,r,t; scanf("%d%d%d",&l,&r,&t);
if(l>r) swap(l,r);
if(l==r) ans[i]=w[l]*(t>=h[l]);
else q[++cnt]={l,r,t,i};
}
work(1,n,1,cnt);
for(int i=1;i<=m;i++) printf("%d\n",ans[i]);
return 0;
}
T4 Range Argmax
抽象,咕。。。
小孩召开法
有机会学多项式再回来做吧。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 零经验选手,Compose 一天开发一款小游戏!
· 因为Apifox不支持离线,我果断选择了Apipost!
· 通过 API 将Deepseek响应流式内容输出到前端