CSP-S 2022
假期计划
简要题意:一个关键点可以通过最多
首先可以
我们记这
那么我们直接枚举
考虑优化暴力,我们发现对于
代码:
#include<bits/stdc++.h>
#define pc(x) putchar(x)
using namespace std;
#define int long long
inline int read()
{
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){f=ch=='-'?-1:f;ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
return x*f;
}
void write(int x)
{
if(x<0){x=-x;pc('-');}
if(x>9)write(x/10);
pc(x%10+48);
}
const int inf=4187201950435737472;
int n,m,k,ans;
int val[2505];
vector<int>e[2505];
bool a[2505][2505];
int dis[2505];bool vis[2505];
priority_queue< pair<int,int> >q;
void dk(int s)
{
memset(dis,0x3f,sizeof dis);
memset(vis,false,sizeof vis);
q.push({0,s});dis[s]=0;
while(!q.empty())
{
int u=q.top().second;q.pop();
if(vis[u])continue; vis[u]=true;
for(int v:e[u])
if(dis[v]>dis[u]+1)
{dis[v]=dis[u]+1;q.push({-dis[v],v});}
}
for(int t=1;t<=n;++t)
if(dis[t]>0&&dis[t]<=k+1)a[s][t]=true;
}
int pmx[2505][2505],pmn[2505][2505],smx[2505][2505],smn[2505][2505];
signed main()
{
freopen("holiday.in","r",stdin);
freopen("holiday.out","w",stdout);
n=read(),m=read(),k=read();val[0]=-inf;
for(int i=2;i<=n;++i)val[i]=read();
for(int i=1;i<=m;++i)
{
int u=read(),v=read();
e[u].push_back(v);
e[v].push_back(u);
}for(int i=1;i<=n;++i)dk(i);
for(int i=2;i<=n;++i)
{
int mx=0,mn=0;
for(int j=1;j<=n;++j)
{
if(val[mx]>val[pmx[i][j]])pmn[i][j]=pmx[i][j],pmx[i][j]=mx;
else if(val[mx]>val[pmn[i][j]])pmn[i][j]=mx;
if(val[mn]>val[pmx[i][j]])pmn[i][j]=pmx[i][j],pmx[i][j]=mn;
else if(val[mn]>val[pmn[i][j]])pmn[i][j]=mn;
if(!a[1][j]||!a[j][i]||i==j)continue;
if(val[j]>val[mx])mn=mx,mx=j;
else if(val[j]>val[mn])mn=j;
}mx=0,mn=0;
for(int j=n;j>=1;--j)
{
if(val[mx]>val[pmx[i][j]])pmn[i][j]=pmx[i][j],pmx[i][j]=mx;
else if(val[mx]>val[pmn[i][j]])pmn[i][j]=mx;
if(val[mn]>val[pmx[i][j]])pmn[i][j]=pmx[i][j],pmx[i][j]=mn;
else if(val[mn]>val[pmn[i][j]])pmn[i][j]=mn;
if(!a[1][j]||!a[j][i]||i==j)continue;
if(val[j]>val[mx])mn=mx,mx=j;
else if(val[j]>val[mn])mn=j;
}
}
for(int i=2;i<=n;++i)
{
int mx=0,mn=0;
for(int j=1;j<=n;++j)
{
if(val[mx]>val[smx[i][j]])smn[i][j]=smx[i][j],smx[i][j]=mx;
else if(val[mx]>val[smn[i][j]])smn[i][j]=mx;
if(val[mn]>val[smx[i][j]])smn[i][j]=smx[i][j],smx[i][j]=mn;
else if(val[mn]>val[smn[i][j]])smn[i][j]=mn;
if(!a[j][1]||!a[i][j]||i==j)continue;
if(val[j]>val[mx])mn=mx,mx=j;
else if(val[j]>val[mn])mn=j;
}mx=0,mn=0;
for(int j=n;j>=1;--j)
{
if(val[mx]>val[smx[i][j]])smn[i][j]=smx[i][j],smx[i][j]=mx;
else if(val[mx]>val[smn[i][j]])smn[i][j]=mx;
if(val[mn]>val[smx[i][j]])smn[i][j]=smx[i][j],smx[i][j]=mn;
else if(val[mn]>val[smn[i][j]])smn[i][j]=mn;
if(!a[j][1]||!a[i][j]||i==j)continue;
if(val[j]>val[mx])mn=mx,mx=j;
else if(val[j]>val[mn])mn=j;
}
}
for(int i=2;i<=n;++i)
for(int j=2;j<=n;++j)
{
if(i==j||!a[i][j])continue;
if(pmx[i][j]==smx[j][i])ans=max(ans,val[i]+val[j]+max(val[pmx[i][j]]+val[smn[j][i]],val[pmn[i][j]]+val[smx[j][i]]));
else ans=max(ans,val[i]+val[j]+val[pmx[i][j]]+val[smx[j][i]]);
}
write(ans),pc('\n');
return 0;
}
策略游戏
全场最简单的题。
维护
可以用 st 表来实现,单次询问
我写的线段树,时间复杂度
代码:
#include<bits/stdc++.h>
#define pc(x) putchar(x)
#define int long long
#define ls (pos<<1)
#define rs (pos<<1|1)
#define pii pair<int,int>
#define fi first
#define se second
using namespace std;
inline int read()
{
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){f=ch=='-'?-1:f;ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
return x*f;
}
void write(int x)
{
if(x<0){x=-x;pc('-');}
if(x>9)write(x/10);
pc(x%10+48);
}
const int inf=2e9;
int n,m,q,ans;
int a[100005],b[100005];
struct node
{
int lmx,lmn,rmn,rmx;
node(int Lmx=inf,int Lmn=-inf,int Rmn=inf,int Rmx=-inf){lmx=Lmx;lmn=Lmn;rmn=Rmn;rmx=Rmx;}
};
struct a_tree
{
int lmx[400005],lmn[400005],rmn[400005],rmx[400005];
void build(int pos,int l,int r)
{
if(l==r)
{
if(a[l]<0){lmx[pos]=lmn[pos]=a[l];rmx[pos]=-inf,rmn[pos]=inf;}
else if(a[l]>0){lmx[pos]=inf,lmn[pos]=-inf;rmx[pos]=rmn[pos]=a[l];}
else {lmx[pos]=lmn[pos]=rmx[pos]=rmn[pos]=0;}
return;
}int mid=(l+r)>>1;
build(ls,l,mid);build(rs,mid+1,r);
lmx[pos]=min(lmx[ls],lmx[rs]);lmn[pos]=max(lmn[ls],lmn[rs]);
rmn[pos]=min(rmn[ls],rmn[rs]);rmx[pos]=max(rmx[ls],rmx[rs]);
}
node merge(node x,node y)
{
node res;
res.lmx=min(x.lmx,y.lmx);res.lmn=max(x.lmn,y.lmn);
res.rmn=min(x.rmn,y.rmn);res.rmx=max(x.rmx,y.rmx);
return res;
}
node query(int pos,int l,int r,int L,int R)
{
if(L<=l&&r<=R)return (node){lmx[pos],lmn[pos],rmn[pos],rmx[pos]};
int mid=(l+r)>>1;node res;
if(L<=mid)res=merge(res,query(ls,l,mid,L,R));
if(R>mid)res=merge(res,query(rs,mid+1,r,L,R));
return res;
}
}tra;
struct b_tree
{
int mn[400005],mx[400005];
void build(int pos,int l,int r)
{
if(l==r){mn[pos]=mx[pos]=b[l];return;}
int mid=(l+r)>>1;
build(ls,l,mid);build(rs,mid+1,r);
mn[pos]=min(mn[ls],mn[rs]);mx[pos]=max(mx[ls],mx[rs]);
}
pii merge(pii x,pii y)
{
pii res={inf,-inf};
res.fi=min(x.fi,y.fi);res.se=max(x.se,y.se);
return res;
}
pii query(int pos,int l,int r,int L,int R)
{
if(L<=l&&r<=R)return {mn[pos],mx[pos]};
int mid=(l+r)>>1;pii res={inf,-inf};
if(L<=mid)res=merge(res,query(ls,l,mid,L,R));
if(R>mid)res=merge(res,query(rs,mid+1,r,L,R));
return res;
}
}trb;
signed main()
{
freopen("game.in","r",stdin);
freopen("game.out","w",stdout);
n=read(),m=read(),q=read();
for(int i=1;i<=n;++i)a[i]=read();
for(int i=1;i<=m;++i)b[i]=read();
tra.build(1,1,n);trb.build(1,1,m);
for(int i=1;i<=q;++i)
{
int l1=read(),r1=read(),l2=read(),r2=read();ans=-2e18;
pii tmp1=trb.query(1,1,m,l2,r2);int mn=tmp1.fi,mx=tmp1.se;
node tmp2=tra.query(1,1,n,l1,r1);
int lmx=tmp2.lmx,lmn=tmp2.lmn,rmn=tmp2.rmn,rmx=tmp2.rmx;
if(l1==r1){write(min(a[l1]*mn,a[l1]*mx)),pc('\n');continue;}
if(l2==r2)
{
if(b[l2]<=0){if(lmx!=inf)ans=max(ans,b[l2]*lmx);if(rmn!=inf)ans=max(ans,b[l2]*rmn);}
else {if(rmx!=-inf)ans=max(ans,b[l2]*rmx);if(lmn!=-inf)ans=max(ans,b[l2]*lmn);}
write(ans),pc('\n');continue;
}
if(mn>=0)ans=rmx!=-inf?mn*rmx:mx*lmn;
else if(mx<=0)ans=lmx!=inf?mx*lmx:mn*rmn;
else{if(rmn!=inf)ans=max(ans,mn*rmn);if(lmn!=-inf)ans=max(ans,mx*lmn);}
write(ans),pc('\n');
}return 0;
}
星战
首先可以发现能进行反攻就是满足所有点的出度为
证明:由每个点都可以无限次虫洞穿梭可得,每个点的出度不为
给每个点随机一个
可以发现要满足上面的条件,就是
那么简单维护下即可,具体实现可以看代码。复杂度
代码:
#include<bits/stdc++.h>
#define pc(x) putchar(x)
#define int unsigned long long
using namespace std;
inline int read()
{
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){f=ch=='-'?-1:f;ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
return x*f;
}
void write(int x)
{
if(x<0){x=-x;pc('-');}
if(x>9)write(x/10);
pc(x%10+48);
}
mt19937_64 rng(time(NULL));
int n,m,q,ans,sum;
int a[500005],s[500005],c[500005];
signed main()
{
freopen("galaxy.in","r",stdin);
freopen("galaxy.out","w",stdout);
n=read(),m=read();
for(int i=1;i<=n;++i)a[i]=rng(),sum+=a[i];
for(int i=1;i<=m;++i)
{
int u=read(),v=read();
s[v]+=a[u];c[v]+=a[u];ans+=a[u];
}q=read();
for(int i=1;i<=q;++i)
{
int op=read(),u=read(),v;if(op&1)v=read();
if(op==1){c[v]-=a[u];ans-=a[u];}
else if(op==3){c[v]+=a[u];ans+=a[u];}
else if(op==2){ans-=c[u];c[u]=0;}
else if(op==4){ans+=s[u]-c[u];c[u]=s[u];}
puts(ans==sum?"YES":"NO");
}
return 0;
}
数据传输
我们设
这里每次询问
我们假设现在位于
当
当
当
发现第二维很小,可以用倍增+矩阵来维护。
我们对矩阵乘法重定义:
那么可以写出转移:
当
当
当
分别预处理出向上和向下的倍增矩阵
代码:
#include<bits/stdc++.h>
#define pc(x) putchar(x)
#define int long long
using namespace std;
inline int read()
{
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){f=ch=='-'?-1:f;ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
return x*f;
}
void write(int x)
{
if(x<0){x=-x;pc('-');}
if(x>9)write(x/10);
pc(x%10+48);
}
const int inf=1e18;
int n,m,q,lg[200005];
vector<int>e[200005];
int a[200005],b[200005][2];
struct matrix
{
int a[3][3];
matrix(int x=0){for(int i=0;i<3;++i)fill(a[i],a[i]+3,inf); if(x){a[0][0]=a[1][1]=a[2][2]=0;}}
int* operator [](int x){return a[x];}
friend matrix operator *(matrix x,matrix y)
{
matrix res;
for(int i=0;i<3;++i)
for(int j=0;j<3;++j)
for(int k=0;k<3;++k)
res[i][j]=min(res[i][j],x[i][k]+y[k][j]);
return res;
}
}up[200005][19],dn[200005][19];
matrix init(int x)
{
matrix res;
if(m==1){res[0][0]=b[x][0];}
else if(m==2){res[0][0]=res[1][0]=b[x][0];res[0][1]=0;}
else if(m==3){res[0][0]=res[1][0]=res[2][0]=b[x][0];res[1][1]=b[x][1];res[0][1]=res[1][2]=0;}
return res;
}
int fa[200005][19],dep[200005];
void dfs(int x,int f)
{
fa[x][0]=f;dep[x]=dep[f]+1;b[x][1]=f?a[f]:inf;
for(int i=1;i<=lg[dep[x]];++i)
fa[x][i]=fa[fa[x][i-1]][i-1];
for(int y:e[x])
{
if(y==f)continue;
dfs(y,x);b[x][1]=min(b[x][1],a[y]);
}up[x][0]=dn[x][0]=init(x);
}
int LCA(int x,int y)
{
if(dep[x]<dep[y])swap(x,y);
for(int i=lg[dep[x]-dep[y]];i>=0;--i)
if(dep[fa[x][i]]>=dep[y])x=fa[x][i];
if(x==y)return x;
for(int i=lg[dep[x]];i>=0;--i)
if(fa[x][i]!=fa[y][i])x=fa[x][i],y=fa[y][i];
return fa[x][0];
}
int SON(int x,int y)
{
for(int i=lg[dep[x]-dep[y]];i>=0;--i)
if(dep[fa[x][i]]>dep[y])x=fa[x][i];
return x;
}
matrix jmp(int x,int y,bool op)
{
matrix res(1);
if(dep[x]<=dep[y])return res;
for(int i=lg[dep[x]-dep[y]];i>=0;--i)
if(dep[fa[x][i]]>=dep[y])
res=op?dn[x][i]*res:res*up[x][i],x=fa[x][i];
return res;
}
matrix query(int x,int y)
{
matrix res(1);
if(x==y||fa[x][0]==y||fa[y][0]==x)return res;
int lca=LCA(x,y);if(x!=lca&&y!=lca)res=init(lca);
return jmp(fa[x][0],lca,0)*res*jmp(fa[y][0],lca,1);
}
signed main()
{
freopen("transmit.in","r",stdin);
freopen("transmit.out","w",stdout);
n=read(),q=read(),m=read();lg[0]=-1;
for(int i=1;i<=n;++i)lg[i]=lg[i>>1]+1;
for(int i=1;i<=n;++i)b[i][0]=a[i]=read();
for(int i=1;i<n;++i)
{
int u=read(),v=read();
e[u].push_back(v);e[v].push_back(u);
}dfs(1,0);
for(int j=1;j<=lg[n];++j)
for(int i=1;i<=n;++i)
up[i][j]=up[i][j-1]*up[fa[i][j-1]][j-1],
dn[i][j]=dn[fa[i][j-1]][j-1]*dn[i][j-1];
for(int i=1;i<=q;++i)
{
int x=read(),y=read();
matrix res;res[0][0]=a[x];
res=res*query(x,y)*init(y);
write(res[0][0]),pc('\n');
}return 0;
}
后记
今年部分分是不是好多啊qwq,似乎不挂分几乎都能300+,然而 HB 的 CSP 没了。
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 百万级群聊的设计实践
· 永远不要相信用户的输入:从 SQL 注入攻防看输入验证的重要性
· 全网最简单!3分钟用满血DeepSeek R1开发一款AI智能客服,零代码轻松接入微信、公众号、小程
· .NET 10 首个预览版发布,跨平台开发与性能全面提升
· 《HelloGitHub》第 107 期