CSP-S 2024 题解
CSP-S 2024 题解
决斗
发现一张卡只有和小的配对才能有贡献,所以sort一遍维护一下比当前小,没被击败的卡的数量就好了
其实可以证明答案就是
超速检测
挂得最狠的一集
将所有超速区间求出来,二分求能被查到的装置区间就好了
中间需要注意想办法避免一下精度误差或者设一下
染色
状态设计典中典,直接设
方程显然,就是
发现滚掉一维之后相当于全局加,全局查最大值,单点取
直接打标记是
擂台游戏
事实上
考虑一下性质,发现可以建出来一个类似线段树的胜负树,这个比较显然
对于
接下来直接考虑拆贡献,发现一个人能赢的充要条件是他能赢到根路上所有自己是擂主的比赛,并且所有自己不是擂主的比赛中,对方子树内有方案使得对方在这一场输
首先前面很好判定,从底到根暴力跳即可,和条件二分开做就好了,关键是后面那一坨的贡献
考虑没有自由位置的怎么做 暴力模拟一遍 其实就是发现一个节点作擂主输的位置是它的关键点,一个节点到关键点一定满足条件一,也就是说除非这个节点到关键点的路径上不满足条件二,它都能对关键点有一个 "可能输的方案",而如果一个节点没有 "可能输的方案",则它的兄弟不满足条件二,而如果这个节点关键点到根不满足条件二,则关键点和这个节点本身都没有贡献
所以依旧是对每一层的点递归做,对于 不满足条件二 的点直接删除它的贡献即可
考虑一下自由位置,其实就是每个祖先擂主节点都是其关键点,所以对每个节点维护其子树内还有没有满足条件二的自由节点即可
由于每个位置只会删除一次,我们这就获得了
所以直接dfs预处理出每个点的关键点即可做到
贴个代码
#include<bits/stdc++.h>
using namespace std;
using llt=long long;
const llt N=200100;
llt n,m,k,T,a[N],b[N],c[N],X[N],P[N],node[N<<2],h[N<<2],Leaf,ans,output,save[N],B,us[N<<2],Get[N<<2];
bool Host[N<<2],tag[N<<2],is[N<<2],vis[N<<2];char C[32][N<<2];vector<llt> vec[N];
void build(llt now)
{
h[now]=1;is[now]=1,vis[now]=node[now]=tag[now]=0;
if(now<=Leaf)
{
build(now<<1),build(now<<1|1);
h[now]=h[now<<1]+1;
}
if(now&1) Host[now]=(C[h[now]][(now-(1<<k-h[now]+1))>>1]=='1');
else Host[now]=(C[h[now]][(now-(1<<k-h[now]+1))>>1]=='0');
}
void dfs(llt now)
{
if(Host[now]) us[h[now]]=now;
else us[h[now]]=us[h[now]+1];
if(now>Leaf) {Get[now]=us[min(b[now-Leaf]+1,N+1)];return;}
dfs(now<<1);dfs(now<<1|1);
}
void Delete(llt now,llt id)
{
if(tag[now]) return;
tag[now]=1;is[now]=0;
if(now>Leaf)
{
llt u=Get[now];
if((now-Leaf<=1<<B)&&!vis[now]) ans-=now-Leaf;
if(now-Leaf<=id) node[u]--;
}
if(now<=Leaf) Delete(now<<1,id),Delete(now<<1|1,id);
}
void update(llt now,llt id)
{
if(is[now]==0||!now) return;
is[now]=is[now<<1]|is[now<<1|1];
if(!is[now]&&!node[now]&&Host[now]&&!tag[now]) Delete(now^1,id);
if(!is[now]) update(now>>1,id);
}
int main()
{
freopen("arena.in","r",stdin);
freopen("arena.out","w",stdout);
scanf("%lld%lld",&n,&m);
for(int i=1;i<=n;i++) scanf("%lld",&a[i]);
for(int i=1;i<=m;i++) scanf("%lld",&c[i]);
for(k=0;(1<<k)<n;k++);Leaf=(1<<k)-1;
for(int i=1;i<=k;i++)
for(int j=0;j<1<<k-i;j++)
scanf(" %c",&C[i][j]);
scanf("%lld",&T);h[0]=10010;
while(T--)
{
build(1);
for(int i=0;i<4;i++) scanf("%lld",&X[i]);
for(int i=1;i<=n;i++) b[i]=a[i]^X[i%4];B=0;ans=1;
dfs(1);
for(int i=1;i<=n;i++)
{
if((1<<B)<i)
{
B++;
for(int j=i;j<=(1<<B);j++)
ans+=j*(!tag[Leaf+j]);
for(auto v:vec[B]) if(!tag[v]&&!vis[v]) ans-=v-Leaf,vis[v]=tag[v]=1;
}
if(!tag[Leaf+i])
{
llt u=Get[Leaf+i];
vec[h[u]].push_back(Leaf+i),node[u]++;
update(Leaf+i,i);if(h[u]<=B) ans-=i,vis[Leaf+i]=1;
}
save[i]=ans;
}
for(int i=1;i<=k;i++) vector<llt>().swap(vec[i]);vector<llt>().swap(vec[h[0]]);
output=0;
for(int i=1;i<=m;i++) output^=(i*save[c[i]]);
printf("%lld\n",output);
}
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
· 周边上新:园子的第一款马克杯温暖上架