NOIP 2024 题解

NOIP 2024 题解

各题的 AC 代码放在了文末。

T1

首先对于两个串都不能动的位置,直接统计是否相等。

对于连续的一段能动的位置,这一段的数可以随便交换,可以预处理每个位置属于哪一段,以及这一段中 0 和 1 的个数。

我们贪心地考虑,优先匹配一个串能动,另一个串不能动的位置。可以感受到,先把不能动的位置匹配掉后,剩下的位置是两个串都可以随便移动的,剩下的位置限制会更松,于是这样是比较优的。

最后处理都能动的位置,我们贪心地能匹配就匹配,因为匹配和失配的贡献都是 1,所以与匹配的顺序无关。

时间复杂度 O(Tn)

T2

按照确定的点分段,考虑到每一段都是独立的。

考虑求每一段合法的方案数,正难则反,用总数减去不合法的方案数。

不合法的方案数就是设左边值为 x,右边为 y,构造一种条件形如当左边为 x 时右边不为 y

这就要求这一段前后连起来,且最后一个值不为 y,大概就是:

Vlen×(V1)

再考虑开头的和结尾的两段,发现怎么取都是合法的。

我们需要快速幂,时间复杂度 O(Tmlogn)

T3

前言

怎么了呢?是不敢面对自己的分数吗,到了元旦才想起来要改这道题。

赛时想到了对每个叶子间的路径计数,如果路径上有关键边那么就是可计数的,对于路径上的方案计数,同时对每个挂在路径上的树的方案计数。可惜我的式子是一个 DP 的形式,我并没有想到式子是可以直接根据各节点的度数计算。


言归正传。

首先如果 k=1,对于一个点它相邻的所有边,有一条初始边是确定了的,剩下的边连成了链,我们不用 DP 就可以计算答案其实是

(di1)!

其中 di 表示点 i 的度数。

而如果 k>1 这样做是会算重的。考虑怎样的生成树是合法的,我们考虑一个点相邻的所有边一定是连成一条链,而关键边一定在链的首尾所对的子树内。

我们称使生成树合法的关键边为有用的关键边,我们把有用的关键边取出来,那么它的两端生成树上连的边,会一直延伸到两个原树上的叶子节点。

我们可以对包含关键边的叶子节点间的路径计数,对于这条链上挂着的子树,和 k=1 的分析是一致的。而对于链上的点,我们已经知道了与之相邻的边连成的链的首尾,而其他边还是任意排列的。所以对于一条两个叶子的路径,答案就是

(di1)!(dv2)!

其中 i除路径外的点v 为路径上的点,这等价于

(di1)!(dv1)1

其中 i所有节点v 是路径上的点。

对于 n=2 特判,否则取一个非叶子节点作为根,每个子树内记录有关键边和没有关键边的乘积。

时间复杂度 O(TnlogV),因为有快速幂。

T4

O(Qnlog2n)O(Qnlogn)

考虑枚举长为 k 的段,求 LCA。
一段的 LCA 就是每次加一个点求 LCA,也可以是合并两个子区间的 LCA。

可以考虑线段树上合并区间 LCA,每次合并用倍增实现 O(logn),也可以在欧拉序上 O(1) 求 LCA。

O(Qn+nlog2n)O(Qn+nlogn)

可以用 ST 表代替线段树,预处理 ST 表合并时可以倍增 O(logn) 也可以 O(1) 求 LCA。

另外,也可以求区间欧拉序的最小最大值,类似欧拉序两个点的 LCA,求 RMQ,这样也能做到 O(nQ+nlogn)

性质 B

上面的做法可以直接通过性质 B。

性质 A

考虑整体二分,就要实现一个数据结构,支持加入或删除一个点,然后查询区间内最长连续段的长度是否大于等于 K

可以用线段树实现,时间复杂度 O((Q+n)log2n)

O((Q+n)log2n)

如果有强大的观察能力或联想能力,可以发现一段区间的 LCA 的深度就是相邻两个点的 LCA 深度的最小值,即

min{depLCA(i,i+1)}

证明就是,考虑这一段区间的 LCA,这段区间的点分布在 LCA 的不同子树内,则一定有 i,i+1 跨在不同子树内。

于是就转化为了性质 A。

O((Q+n)logn)

考虑对于每个点 i,设 si=depLCA(i,i+1),求出 minlijri{sj}=si 的极大区间 (li,ri,si)

设询问区间为 (L,R),就是求 (lr,ri,si)(L,R) 的交大于等于 K 的区间的最大 si

分类讨论,当 riR 时,要满足

L+K1riRrili+1K

riR 时,要满足

liRK+1riR

前者对 rili+1,K 扫描线,后者对 ri,R 扫描线。

具体地,把做扫描线的量排序,然后双指针把另一个量加入数据结构中或在数据结构中查询。

前者 L+K1riR 可以线段树,后者 liRK 可以树状数组。

K=1 时,需要特殊处理,直接用数据结构查区间最值。可选 ST 表。

时间复杂度 O((Q+n)logn)


T1:

const int N=1e5+5;
char a[N],b[N],c[N],d[N];
int m1[N],m2[N];
int t1,t2;
int c1[N],c2[N],c3[N],c4[N];
signed main(){
// freopen("edit.in","r",stdin);
// freopen("edit.out","w",stdout);
read(T);
while(T--){
read(n);
scanf("%s%s%s%s",a+1,b+1,c+1,d+1);
int ans=0;
t1=1,t2=1;
c1[1]=c2[1]=c3[1]=c4[1]=0;
fo(i,1,n){
if(c[i]=='1')m1[i]=t1,c1[t1]+=a[i]=='1',c2[t1]+=a[i]=='0';
else ++t1,m1[i]=c1[t1]=c2[t1]=0;
if(d[i]=='1')m2[i]=t2,c3[t2]+=b[i]=='1',c4[t2]+=b[i]=='0';
else ++t2,m2[i]=c3[t2]=c4[t2]=0;
}
fo(i,1,n){
int j=m1[i],k=m2[i];
if(c[i]=='0'&&d[i]=='0')ans+=a[i]==b[i];
else if(c[i]=='0'){
if(a[i]=='0'&&c4[k])c4[k]--,ans++;
if(a[i]=='1'&&c3[k])c3[k]--,ans++;
}
else if(d[i]=='0'){
if(b[i]=='1'&&c1[j])c1[j]--,ans++;
if(b[i]=='0'&&c2[j])c2[j]--,ans++;
}
}
fo(i,1,n){
int j=m1[i],k=m2[i];
if(c[i]=='1'&&d[i]=='1'){
if(c1[j]&&c3[k])c1[j]--,c3[k]--,ans++;
else if(c2[j]&&c4[k])c2[j]--,c4[k]--,ans++;
}
}
write(ans,'\n');
}
return 0;
}

T2:

signed main(){
// freopen("assign.in","r",stdin);
// freopen("assign.out","w",stdout);
read(T);
while(T--){
read(n,m,V);
fo(i,1,m){
read(a[i].first,a[i].second);
}
sort(a+1,a+1+m);
int flag=0;
fo(i,1,m-1){
if(a[i].first==a[i+1].first&&a[i].second!=a[i+1].second)flag=1;
}
if(flag){
write("0\n");
continue;
}
m=unique(a+1,a+1+m)-a-1;
int ans=1;
fo(i,1,m-1){
int len=a[i+1].first-a[i].first;
ans=(ll)ans*(pow1(V,2*len)-(ll)pow1(V,len-1)*(V-1)%mod)%mod;
}
ans=(ll)ans*pow1(V,2*(a[1].first-1))%mod*pow1(V,2*(n-a[m].first))%mod;
write((ans+mod)%mod,'\n');
}
return 0;
}

T3:

const int mod=1e9+7;
const int N=1e5+5;
vp g[N];
int cid,T,n,K,key[N],deg[N];
int pow1(int x,int y){
int res=1;
for(;y;y>>=1,x=(ll)x*x%mod)if(y&1)res=(ll)res*x%mod;
return res;
}
int sum,f1[N],f2[N];
void dfs(int x,int y) {
int flag=0;
f1[x]=f2[x]=0;
int s1=0,s2=0;
for(auto v:g[x]) {
if(v.first==y) continue;
flag=1;
dfs(v.first,x);
int t1=f1[v.first],t2=f2[v.first];
if(key[v.second])t1=(t1+t2)%mod,t2=0;
sum=(sum+(ll)s1*(t1+t2)%mod*pow1(deg[x]-1,mod-2))%mod;
sum=(sum+(ll)s2*(t1)%mod*pow1(deg[x]-1,mod-2))%mod;
s1=(s1+t1)%mod;
s2=(s2+t2)%mod;
f2[x]=(f2[x]+(ll)t2*pow1(deg[x]-1,mod-2))%mod;
f1[x]=(f1[x]+(ll)t1*pow1(deg[x]-1,mod-2))%mod;
}
if(!flag) {
f1[x]=0,f2[x]=1;
}
}
int fac[N];
signed main(){
usefile("traverse");
read(cid,T);
while(T--) {
read(n,K);
fo(i,1,n)deg[i]=0,g[i].clear();
fu(i,1,n){
int u,v; read(u,v);
g[u].pb({v,i});
g[v].pb({u,i});
deg[u]++,deg[v]++;
key[i]=0;
}
fo(i,1,K){
int e; read(e);
key[e]=1;
}
if(n==2) {write("1\n"); continue;};
int prod=1;
fac[0]=1;
fo(i,1,n)fac[i]=(ll)fac[i-1]*i%mod;
fo(i,1,n)prod=(ll)prod*fac[deg[i]-1]%mod;
fo(i,1,n)if(deg[i]!=1) {
sum=0;
dfs(i,0);
write((ll)prod*sum%mod,'\n');
break;
}
}
return 0;
}

T4:

const int N=5e5+5;
int n,Q;
vector<int> g[N];
int fa[N][19];
int dep[N];
int lca(int x,int y){
if(dep[x]<dep[y])swap(x,y);
for(int i=dep[x]-dep[y],j=0;i;i>>=1,j++)if(i&1)x=fa[x][j];
if(x==y)return x;
fd(i,18,0)if(fa[x][i]!=fa[y][i]){
x=fa[x][i],y=fa[y][i];
}
return fa[x][0];
}
void dfs(int x,int y){
fa[x][0]=y;
dep[x]=dep[y]+1;
fo(i,1,18)fa[x][i]=fa[fa[x][i-1]][i-1];
for(int v:g[x]){
if(v!=y)dfs(v,x);
}
}
int ans[N];
int v[N];
struct arr{
int l,r,k,num;
}a[N],q[N];
stack<pair<int,int> > stk;
struct BIT{
int lowbit(int x){
return x&(-x);
}
int s[N];
void update(int x,int y){
while(x<n)s[x]=max(s[x],y),x+=lowbit(x);
}
int query(int x){
int _s=0;
while(x)_s=max(_s,s[x]),x-=lowbit(x);
return _s;
}
}b;
struct tree{
#define ls (x<<1)
#define rs (ls|1)
#define mid ((l+r)>>1)
int s[N*4];
void update(int x,int l,int r,int y,int z){
if(l==r){
s[x]=max(s[x],z);
return;
}
if(y<=mid)update(ls,l,mid,y,z);
else update(rs,mid+1,r,y,z);
s[x]=max(s[ls],s[rs]);
}
int query(int x,int l,int r,int L,int R){
if(L<=l&&r<=R)return s[x];
if(R<l||r<L)return 0;
return max(query(ls,l,mid,L,R),query(rs,mid+1,r,L,R));
}
}tr;
struct ST{
int mx[19][N];
void make(){
fo(i,1,n)mx[0][i]=dep[i];
fo(i,1,__lg(n)){
fo(j,1,n-(1<<i)+1){
mx[i][j]=max(mx[i-1][j],mx[i-1][j+(1<<i-1)]);
}
}
}
int get(int l,int r){
int len=r-l+1;
return max(mx[__lg(len)][l],mx[__lg(len)][r-(1<<__lg(len))+1]);
}
}ST;
signed main(){
// freopen("query.in","r",stdin);
// freopen("query.out","w",stdout);
read(n);
fo(i,1,n-1){
int u,v;
read(u,v);
g[u].push_back(v);
g[v].push_back(u);
}
dfs(1,0);
fo(i,1,n-1){
v[i]=dep[lca(i,i+1)];
while(stk.size()&&v[i]<=stk.top().first)stk.pop();
if(stk.size())a[i].l=stk.top().second+1;
else a[i].l=1;
stk.push({v[i],i});
a[i].k=v[i];
}
while(stk.size())stk.pop();
fd(i,n-1,1){
while(stk.size()&&v[i]<=stk.top().first)stk.pop();
if(stk.size())a[i].r=stk.top().second-1;
else a[i].r=n-1;
stk.push({v[i],i});
}
sort(a+1,a+n,[](arr x,arr y){
return x.r>y.r;
});
ST.make();
read(Q);
fo(i,1,Q){
read(q[i].l),read(q[i].r),read(q[i].k);
q[i].num=i;
if(q[i].k==1){
ans[i]=ST.get(q[i].l,q[i].r);
}
q[i].r--;
q[i].k--;
}
sort(q+1,q+1+Q,[](arr x,arr y){
return x.r>y.r;
});
int st=1;
fo(i,1,n-1){
while(st<=Q&&q[st].r>a[i].r){
if(!q[st].k){
++st; continue;
}
ans[q[st].num]=max(ans[q[st].num],b.query(q[st].r-q[st].k+1));
++st;
}
b.update(a[i].l,a[i].k);
}
while(st<=Q){
if(!q[st].k){
++st; continue;
}
ans[q[st].num]=max(ans[q[st].num],b.query(q[st].r-q[st].k+1));
++st;
}
sort(a+1,a+n,[](arr x,arr y){
return x.r-x.l+1>y.r-y.l+1;
});
st=1;
sort(q+1,q+1+Q,[](arr x,arr y){
return x.k>y.k;
});
fo(i,1,n-1){
while(st<=Q&&q[st].k>a[i].r-a[i].l+1){
if(!q[st].k){
++st; continue;
}
ans[q[st].num]=max(ans[q[st].num],tr.query(1,1,n-1,q[st].l+q[st].k-1,q[st].r));
++st;
}
tr.update(1,1,n-1,a[i].r,a[i].k);
}
while(st<=Q){
if(!q[st].k){
++st; continue;
}
ans[q[st].num]=max(ans[q[st].num],tr.query(1,1,n-1,q[st].l+q[st].k-1,q[st].r));
++st;
}
fo(i,1,Q)write(ans[i],'\n');
return 0;
}
posted @   dengchengyu  阅读(129)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 一文读懂知识蒸馏
· 终于写完轮子一部分:tcp代理 了,记录一下
点击右上角即可分享
微信分享提示