CSP模拟46
开题顺序 3-2-1-4,感觉这套题挺草的。
T1 染色(color)
将限制看成边。
考虑质数集中只有一个偶质数
然后其他的质数都是奇数,则其他限制一定是从一条链指向另一条链,则只要一条链颜色集为
发现
#include<stdio.h>
#include<iostream>
#include<algorithm>
using namespace std;
const int MAXN=1e4+10;
int n;
int main()
{
freopen("color.in","r",stdin);
freopen("color.out","w",stdout);
cin.tie(0),cout.tie(0);
ios::sync_with_stdio(0);
cin>>n;
if(n<=6)
{
if(n==1) cout<<1<<endl<<"1"<<endl;
if(n==2) cout<<1<<endl<<"1 1"<<endl;
if(n==3) cout<<2<<endl<<"1 1 2"<<endl;
if(n==4) cout<<2<<endl<<"1 1 2 2"<<endl;
if(n==5) cout<<3<<endl<<"1 1 2 2 3"<<endl;
if(n==6) cout<<3<<endl<<"1 1 2 2 3 3"<<endl;
}
else
{
cout<<4<<endl;
for(register int i=1;i<=n;++i)
cout<<(i-1)%4+1<<' ';
cout<<endl;
}
return 0;
}
开题时一下就注意到只有一个偶质数,但没想到解法,后面写完 T2 突然想到了。
T2 序列(array)
考虑
此时肯定是优先使得小的
当
感性理解发现是可能(好像假了)是单峰函数,三分求解,
但这个连续函数值相等的长度的上界不清楚,这样处理可能属于投机取巧。
#include<stdio.h>
#include<iostream>
#include<algorithm>
using namespace std;
const int MAXN=2e5+10;
int T,n,m,k,a[MAXN],sum;
long long d;
inline long long f(long long x)
{
long long D=d-x*sum,ans=x*(k+m);
for(register int i=1;i<=m;++i)
{
long long K=min(D/a[i],1ll*n-x);
ans+=K,D-=K*a[i];if(!K) break;
}
return ans;
}
int main()
{
freopen("array.in","r",stdin);
freopen("array.out","w",stdout);
cin.tie(0),cout.tie(0);
ios::sync_with_stdio(0);
cin>>T;
while(T--)
{
cin>>n>>m>>k>>d;sum=0;
for(register int i=1;i<=m;++i)
cin>>a[i],sum+=a[i];
sort(a+1,a+1+m);
int l=0,r=min(1ll*n,d/sum);long long ans=0;
while(l+50<r)
{
int lmid=l+(r-l)/3,rmid=r-(r-l)/3;
ans=max(ans,max(f(lmid),f(rmid)));
(f(lmid)<f(rmid))?l=lmid+1:r=rmid-1;
}
for(register int i=l;i<=r;++i) ans=max(ans,f(i));
cout<<ans<<endl;
}
return 0;
}
赛时写了二分,但函数值不一定不等,所以寄了。幸好加了特判暴力,只挂了 5pts。
T3 树上询问(query)
感觉挺一眼的,5k 说应该放 T1,臣附议。
记
第一部分
#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
const int MAXN=3e5+10,MAXT=6.5e6+10;
int n,m,fa[MAXN],f[MAXN][20],dep[MAXN];
vector <int> v[MAXN];
struct tree
{
int root[MAXN],cnt,t[MAXT],ls[MAXT],rs[MAXT],L,R;
inline void push_up(int p){t[p]=t[ls[p]]+t[rs[p]];return ;}
void change(int l,int r,int p,int q,int x)
{
if(l==r){t[q]=t[p]+1;return ;}
int mid=(l+r)>>1;ls[q]=ls[p],rs[q]=rs[p];
if(x<=mid) change(l,mid,ls[p],ls[q]=++cnt,x);
else change(mid+1,r,rs[p],rs[q]=++cnt,x);
push_up(q);return ;
}
int query(int l,int r,int p,int x)
{
if(x<l||x>r) return 0;
if(l==r) return t[p];
int mid=(l+r)>>1;
if(x<=mid) return query(l,mid,ls[p],x);
else return query(mid+1,r,rs[p],x);
}
inline void upd(int x,int z)
{
root[x]=++cnt;
change(L,R,root[fa[x]],root[x],z);
return ;
}
inline int Q(int x,int y,int z)
{return query(L,R,root[x],z)-query(L,R,root[y],z);}
}a,b;
void dfs(int x)
{
dep[x]=dep[fa[x]]+1,f[x][0]=fa[x];
for(register int i=1;i<=__lg(dep[x]);++i)
f[x][i]=f[f[x][i-1]][i-1];
a.upd(x,dep[x]+x),b.upd(x,x-dep[x]);
for(int y:v[x]) if(y!=fa[x]) fa[y]=x,dfs(y);
return ;
}
inline int lca(int x,int y)
{
if(dep[x]<dep[y]) swap(x,y);
while(dep[x]>dep[y]) x=f[x][__lg(dep[x]-dep[y])];
if(x==y) return x;
for(register int i=__lg(dep[x]);i>=0;--i)
if(f[x][i]!=f[y][i]) x=f[x][i],y=f[y][i];
return f[x][0];
}
int main()
{
freopen("query.in","r",stdin);
freopen("query.out","w",stdout);
cin.tie(0),cout.tie(0);
ios::sync_with_stdio(0);
cin>>n>>m;
a.L=2,a.R=n<<1,b.L=1-n,b.R=n-1;
for(register int i=1;i<n;++i)
{
int x,y;cin>>x>>y;
v[x].push_back(y),v[y].push_back(x);
}
dfs(1);
for(register int i=1;i<=m;++i)
{
int l,r,L,ans=0;cin>>l>>r;L=lca(l,r);
ans+=a.Q(l,fa[L],dep[l]);
ans+=b.Q(r,L,dep[l]-(dep[L]<<1));
cout<<ans<<endl;
}
return 0;
}
主席树多个
T4 网络(network)
感觉这题是唯一一道有意义的难点的题,还挺神的,但题解还挺烂的,看了 Chen_jr 学长的题解,膜拜。
将每次操作抽象出来,就是限制
发现仅要求
考虑一组操作
最后对于每一组中任意选定一个点带电,答案一定满足条件。
考虑如何输出方案,我们从后往前处理,相当于与原来相反。即对于一组操作
然后发现尽管进行这次操作后我们确定了带电的是哪个点,但是在这次操作前,
//这题写了点注释
#include<stdio.h>
#include<iostream>
#include<algorithm>
using namespace std;
const int MAXN=5e5+10,MAXM=5e6+10;
int n,m,x[MAXM],y[MAXM],p[MAXN],ans[MAXM];
int opx[MAXM],opy[MAXM];bool b[MAXN];
int main()
{
#ifdef ONLINE_JUDGE
freopen("network.in","r",stdin);
freopen("network.out","w",stdout);
cin.tie(0),cout.tie(0);
ios::sync_with_stdio(0);
#endif
cin>>n>>m;
for(register int i=1;i<=n;++i)
{
if(i&1) p[i]=(i+1<=n)?i+1:0;
else p[i]=(i-1);
}
if(n&1) p[0]=n;//n 为奇数就放个 0 进去
for(register int i=1;i<=m;++i)
{
cin>>x[i]>>y[i];
//opx[i] 指在进行第 i 个操作前的 p[x],opy[i] 同理
opx[i]=p[x[i]],opy[i]=p[y[i]];
p[x[i]]=y[i],p[y[i]]=x[i];
p[opx[i]]=opy[i],p[opy[i]]=opx[i];
}
//随意钦定,这里判断大于可以保证只选一个点
for(register int i=1;i<=n;++i) if(i>p[i]) b[i]=true;
for(register int i=m;i;--i)
{
if(b[y[i]]) ans[i]=1;
if(!b[opx[i]]) b[x[i]]=true,b[y[i]]=false;
if(!b[opy[i]]) b[y[i]]=true,b[x[i]]=false;
p[x[i]]=opx[i],p[y[i]]=opy[i];
p[opx[i]]=x[i],p[opy[i]]=y[i];
}
cout<<"YES"<<endl;
for(register int i=1;i<=m;++i) cout<<ans[i];
cout<<endl;return 0;
}
考场写了个很奇怪的东西,暴力分都没拿到。话说这题应该很难场切吧。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· winform 绘制太阳,地球,月球 运作规律
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· 写一个简单的SQL生成工具
· AI 智能体引爆开源社区「GitHub 热点速览」