6月6日模拟赛题解

P4315 月下“毛景树”

没代码能力,写不动,赛时没写。
注意 pushdown 即可。

#include<bits/stdc++.h>
inline int read(){
	char ch=getchar();int x=0,f=1;
	for(;ch<'0'||ch>'9';ch=getchar())if(ch=='-')f=-1;
	for(;ch>='0'&&ch<='9';ch=getchar())x=(x<<3)+(x<<1)+(ch^48);
	return x*f;
}
const int N=1e5+10;
int n,head[N],tot,dfn[N],top[N],dep[N],son[N],siz[N],fa[N],w[N],rnk[N];
std::pair<int,int> tr[N];
struct E{int v,next,w;}e[N<<1];
inline void add(int u,int v,int w){e[++tot]={v,head[u],w},head[u]=tot;}
inline void dfs1(int x){
	siz[x]=1;
	int y;
	for(int i=head[x];i;i=e[i].next){
		if(!dep[y=e[i].v]){
			w[y]=e[i].w;
			dep[y]=dep[x]+1;fa[y]=x;dfs1(y);siz[x]+=siz[y];
			if(!son[x]||siz[y]>siz[son[x]])son[x]=y;
		}
	}
}
inline void dfs2(int x,int t){
	top[x]=t;dfn[x]=++tot;rnk[tot]=x;
	if(!son[x])return;
	dfs2(son[x],t);
	int y;
	for(int i=head[x];i;i=e[i].next){
		y=e[i].v;
		if(y!=fa[x]&&y!=son[x])dfs2(y,y);
	}
}
struct Tree{int push,modi,max;}t[N<<2];
inline void pushdown(int p){
	if(t[p].push>=0){
		t[p<<1].modi=t[p<<1|1].modi=0;
		t[p<<1].max=t[p<<1|1].max=t[p<<1].push=t[p<<1|1].push=t[p].push;
	}
	if(t[p].modi){
		t[p<<1].modi+=t[p].modi,t[p<<1|1].modi+=t[p].modi;
		t[p<<1].max+=t[p].modi,t[p<<1|1].max+=t[p].modi;
	}
	t[p].push=-1,t[p].modi=0;
}
inline void update(int p){
	t[p].max=std::max(t[p<<1].max,t[p<<1|1].max);	
}
inline void build(int p,int l,int r){
	t[p].push=-1;
	if(l==r){t[p].max=w[rnk[l]];t[p].push=-1;return;}
	int mid=l+r>>1;
	build(p<<1,l,mid),build(p<<1|1,mid+1,r);
	update(p);
}
inline int ask(int p,int l,int r,int x,int y){
	int res=-2e9;
	if(l>=x&&r<=y){return t[p].max;}
	pushdown(p);
	int mid=l+r>>1;
	if(x<=mid)res=std::max(res,ask(p<<1,l,mid,x,y));
	if(y>mid)res=std::max(res,ask(p<<1|1,mid+1,r,x,y));
	return res;
}
inline int query(int u,int v){
	int res=-2e9;
	while(top[u]!=top[v]){
		if(dep[top[u]]<dep[top[v]])std::swap(u,v);
		res=std::max(res,ask(1,1,n,dfn[top[u]],dfn[u]));
		u=fa[top[u]];
	}
	if(u==v)return res;
	if(dep[u]>dep[v])std::swap(u,v);
	res=std::max(res,ask(1,1,n,dfn[son[u]],dfn[v]));
	return res;
}
inline void change1(int p,int l,int r,int x,int y,int c){
	if(l>=x&&r<=y){t[p].modi+=c;t[p].max+=c;return;}
	pushdown(p);
	int mid=l+r>>1;
	if(x<=mid)change1(p<<1,l,mid,x,y,c);
	if(y>mid)change1(p<<1|1,mid+1,r,x,y,c);
	update(p);
}
inline void change2(int p,int l,int r,int x,int y,int c){
	if(l>=x&&r<=y){t[p].modi=0;t[p].push=c;t[p].max=c;return;}
	pushdown(p);
	int mid=l+r>>1;
	if(x<=mid)change2(p<<1,l,mid,x,y,c);
	if(y>mid)change2(p<<1|1,mid+1,r,x,y,c);
	update(p);
}
inline void modify(int u,int v,int c,int flag){
	while(top[u]!=top[v]){
		if(dep[top[u]]<dep[top[v]])std::swap(u,v);
		if(flag)change1(1,1,n,dfn[top[u]],dfn[u],c);
		else change2(1,1,n,dfn[top[u]],dfn[u],c);
		u=fa[top[u]];
	}
	if(u==v)return;
	if(dep[u]>dep[v])std::swap(u,v);
	if(flag)change1(1,1,n,dfn[son[u]],dfn[v],c);
	else change2(1,1,n,dfn[son[u]],dfn[v],c);
}
int main(){
	// freopen("in.in","r",stdin),freopen("out.out","w",stdout);
	std::ios::sync_with_stdio(false);std::cin.tie(0),std::cout.tie(0);
	std::cin>>n;
	dep[1]=1;
	for(int i=1;i<n;++i){
		int u,v,w;std::cin>>u>>v>>w;
		tr[i]={u,v};
		add(u,v,w);add(v,u,w);
	}
	dfs1(1);tot=0;
	dfs2(1,1);
	build(1,1,n);
	while(1){
		std::string s;
		std::cin>>s;
		if(s=="Max"){
			int u,v;std::cin>>u>>v;
			std::cout<<query(u,v)<<"\n";
		}
		if(s=="Change"){
			int k,c;std::cin>>k>>c;
			modify(tr[k].first,tr[k].second,c,0);
		}
		if(s=="Cover"){
			int u,v,c;std::cin>>u>>v>>c;
			modify(u,v,c,0);
		}
		if(s=="Add"){
			int u,v,c;std::cin>>u>>v>>c;
			modify(u,v,c,1);
		}
		if(s=="Stop"){
			exit(0);
		}
	}
}

上课安排

考虑数学归纳法。

  • \(n=5\) 时,可以找出 \(\{1\},\{2,3\},\{3,4,5\}\),对于 \(n=7\) 时,可以在每个集合后加一个 \(7\),然后将 \(6\) 作为一个单独的集合,再加上一个 \(\{1,2,3,4,5\}\) 这样的集合。对于所有奇数,以此类推。
  • \(n=4\) 时,可以找出 \(\{1\},\{2,3\}\),对于 \(n=6\) 时,可以在每个集合后加一个 \(7\),然后将 \(5\) 作为一个单独的集合,再加上 \(\{1,2,3,4\}\) 这样的集合。对于所有偶数,以此类推。
    代码是打表找的规律(赛时快读锅了)。
#include<bits/stdc++.h>
inline int read(){
    int x=0,f=1;char ch=getchar();
    for(;ch<'0'||ch>'9';ch=getchar())if(ch=='-')f=-1;
    for(;ch>='0'&&ch<'9';ch=getchar())x=x*10+ch-'0';
    return x*f;
}
const int N=1e3+10;
int main(){
    freopen("course.in","r",stdin);freopen("course.out","w",stdout);
	int n;
	std::cin>>n;
    int ans=n-2;
    std::cout<<ans<<'\n';
    if(n&1){
        for(int i=1;i<=ans;++i){
            std::cout<<i<<' ';
            if(i<=n/2){
                int zc=n-(i*2-1);
                std::cout<<zc<<' ';
                zc+=3;
                for(int j=1;j<=i-1;++j,zc+=2)std::cout<<zc<<' ';std::cout<<'\n';
            }
            else{
                int zc=i-n/2+1;zc=zc*2-1;
                for(int j=1;j<=zc;++j)std::cout<<j<<' ';
                int w=zc+4;
                for(;w<=n;w+=2)std::cout<<w<<' ';std::cout<<'\n';
            }
        }
    }else{
        for(int i=1;i<=ans;++i){
            std::cout<<i<<' ';
            if(i<=n/2){
                int zc=n-(i*2-1);
                std::cout<<zc<<' ';
                zc+=3;
                for(int j=1;j<=i-1;++j,zc+=2)std::cout<<zc<<' ';std::cout<<'\n';
            }
            else{
                int zc=i-n/2+1;zc=zc*2;
                for(int j=1;j<=zc;++j)std::cout<<j<<' ';
                int w=zc+4;
                for(;w<=n;w+=2)std::cout<<w<<' ';std::cout<<'\n';
            }
        }
    }
}

P3360 偷天换日

递归输入建图,然后对于叶子做背包,向父亲直接枚举转移即可(赛时快读锅了)。

#include<bits/stdc++.h>
#define int long long
inline int read(){
    int x=0,f=1;char ch=getchar();
    for(;ch<'0'||ch>'9';ch=getchar())if(ch=='-')f=-1;
    for(;ch>='0'&&ch<='9';ch=getchar())x=x*10+ch-'0';
    return x*f;
}
const int N=705;
int f[N][N],tot,head[N],max,cnt=1,a[N],v[N],b[305][40][N],lson[N],rson[N],wlson[N],wrson[N];
struct E{int v,next,w;}e[N];
inline void add(int u,int v,int w){w*=2;e[++tot]={v,head[u],w};head[u]=tot;}
inline void bp(int x,int t){
	int zc=0;
    for(int i=1;i<=t;++i){
        a[i]=read(),v[i]=read();
        zc+=v[i];
    }
    b[x][1][v[1]]=a[1];
    for(int i=2;i<=t;++i){
        for(int j=0;j<=zc;++j){
            b[x][i][j]=b[x][i-1][j];
            if(j>=v[i]){
                b[x][i][j]=std::max(b[x][i][j],b[x][i-1][j-v[i]]+a[i]);
            }
        }
    }
    for(int i=0;i<=zc;++i)f[x][i]=b[x][t][i];
}
inline void init(int x){
    int w=read();
    add(x,++cnt,w);
    int zc=cnt;
    int t=read();
    if(!t){
        init(zc);
        init(zc);
    }else{
        bp(zc,t);
    }
}
inline void dfs(int x){
    if(lson[x]){
    	dfs(lson[x]);
    	 for(int i=0;i+wlson[x]<=max;++i){
            f[x][i+wlson[x]]=f[lson[x]][i];
         }
	}
    if(rson[x]){
        dfs(rson[x]);
         for(int i=max;i>=0;--i){
             for(int k=1;k<=i;++k){
             	if(i+wrson[x]>max)continue;
                 f[x][i+wrson[x]]=std::max(f[x][i+wrson[x]],f[x][i-k]+f[rson[x]][k]);
             }
         }
    }
}
signed main(){
    // freopen("in.in","r",stdin);freopen("out.out","w",stdout);
    max=read()-1;init(1);
    for(int i=1;i<=cnt;++i){
    	int j=head[i];
    	if(!j){continue;}
    	lson[i]=e[j].v;wlson[i]=e[j].w;
        j=e[j].next;
    	if(j)rson[i]=e[j].v,wrson[i]=e[j].w;
	}
    dfs(1);
    int ans=0;
    for(int i=max;i>=0;--i){
        if(f[1][i]){
            ans=std::max(f[1][i],ans);
        }
    }
    std::cout<<ans<<'\n';
}

P2894 [USACO08FEB] Hotel G

发的题解是线段树合并,但我感觉没那意思。
跟山海经(小白逛公园)有些相似,考虑维护区间最长 \(0\) 的连续段,修改直接做,对于查询如果当前节点不满足则不合法,满足则查找左儿子,如果左儿子的值满足直接进去找,否则查看右儿子是否满足,如果满足进去查询并返回查询与当前点答案的较小值,如果不满足就是当前节点的答案。

#include<bits/stdc++.h>
inline int read(){
	char ch=getchar();int x=0,f=1;
	for(;ch<'0'||ch>'9';ch=getchar())if(ch=='-')f=-1;
	for(;ch>='0'&&ch<='9';ch=getchar())x=(x<<3)+(x<<1)+(ch^48);
	return x*f;
}
const int N=5e4+10;
int n,m;
struct Tree{int ls,rs,s,ans,tag,l,r;}t[N<<5];
inline void update(Tree &sum,Tree a,Tree b){
	sum.ls=a.ls;
	if(a.ls==a.r)sum.ls=std::max(b.ls,sum.ls);
	sum.rs=b.rs;
	if(b.rs==b.l&&a.rs)sum.rs=std::min(a.rs,sum.rs);
	sum.ans=a.ans;sum.s=a.s;
	if(sum.ans<b.ans)sum.ans=b.ans,sum.s=b.s;
	if(a.rs&&b.ls&&sum.ans<b.ls-a.rs+1)sum.ans=b.ls-a.rs+1,sum.s=a.rs;
}
inline void build(int p,int l,int r){
	t[p].l=l,t[p].r=r;t[p].tag=-1;
	if(l==r){t[p]={l,l,l,1,-1,l,r};return;}
	int mid=l+r>>1;
	build(p<<1,l,mid);build(p*2+1,mid+1,r);
	update(t[p],t[p<<1],t[p<<1|1]);
}
inline void pushdown(int p,int l,int r){
	if(t[p].tag>=0){
		int mid=l+r>>1;
		if(!t[p].tag){t[p<<1]={mid,l,l,mid-l+1,t[p].tag,t[p<<1].l,t[p<<1].r};t[p<<1|1]={r,mid+1,mid+1,r-mid,t[p].tag,t[p<<1|1].l,t[p<<1|1].r};}
		else t[p<<1]={0,0,0,0,t[p].tag,t[p<<1].l,t[p<<1].r},t[p<<1|1]={0,0,0,0,t[p].tag,t[p<<1|1].l,t[p<<1|1].r};
		t[p].tag=-1;
	}
}
inline void change(int p,int l,int r,int x,int y,int c){
	if(l>=x&&r<=y){
		if(c){t[p]={0,0,0,0,c,l,r};}
		else {t[p]={r,l,l,r-l+1,c,l,r};}
		return;
	}
	pushdown(p,l,r);
	int mid=l+r>>1;
	if(x<=mid)change(p<<1,l,mid,x,y,c);
	if(y>mid)change(p<<1|1,mid+1,r,x,y,c);
	update(t[p],t[p<<1],t[p<<1|1]);
}
inline int query(int p,int l,int r,int x){
	if(l==r){return t[p].s;}
	if(t[p].ans<x){return 0;}
	pushdown(p,l,r);
	int mid=l+r>>1;
	if(t[p<<1].ans>=x){return query(p<<1,l,mid,x);}
	else{
		if(t[p<<1|1].ls&&t[p<<1].rs&&t[p<<1|1].ls-t[p<<1].rs+1>=x)return t[p<<1].rs;
		if(t[p<<1|1].ans>=x)return std::min(query(p<<1|1,mid+1,r,x),t[p].s);
		else return t[p].s;
	}
}
int main(){
	freopen("hotel.in","r",stdin),freopen("hotel.out","w",stdout);
	std::ios::sync_with_stdio(false);std::cin.tie(0),std::cout.tie(0);
	n=read(),m=read();
	build(1,1,n);
	for(int i=1;i<=m;++i){
		int op=read();
		if(op==1){
			int len=read();
			int ans=query(1,1,n,len);
			if(ans)change(1,1,n,ans,ans+len-1,1);
			std::cout<<ans<<'\n';
		}else{
			int l=read(),r=read()+l-1;
			r=std::min(r,n);
			change(1,1,n,l,r,0);
		}
	}
}

P4303 [AHOI2006] 基因匹配

赛时没咋看,感觉比前面四道加起来有深意。
根据性质,每个数出现 \(5\) 次,所以只会在这 \(5\) 个位置匹配成功。
具体来说,记一下 \(a\) 串的每个数出现的位置,设 \(f_i\) 表示匹配到 \(a\) 串的第 \(i\) 个位置时的最长 LCS 长度,然后遍历 \(b\) 串,查找 \(b_i\)\(a\) 串中的位置 \(x\),有 \(f_x=\max(f_k+1)(k\le x-1)\),(注意倒序)上数据结构维护即可。

#include<bits/stdc++.h>
inline int read(){
	char ch=getchar();int x=0,f=1;
	for(;ch<'0'||ch>'9';ch=getchar())if(ch=='-')f=-1;
	for(;ch>='0'&&ch<='9';ch=getchar())x=(x<<3)+(x<<1)+(ch^48);
	return x*f;
}
const int N=1e5+10;
int n,f[N];
std::vector<int> v_a[N],v_b[N];
struct Tree{int ans;}t[N<<2];
inline void change(int p,int l,int r,int pos,int x){
	if(l==r){t[p].ans=x;return;}
	int mid=l+r>>1;
	if(pos<=mid)change(p*2,l,mid,pos,x);
	else change(p*2+1,mid+1,r,pos,x);
	t[p].ans=std::max(t[p*2].ans,t[p*2+1].ans);
}
inline int query(int p,int l,int r,int x,int y){
	if(x>y)return 0;
	if(l>=x&&r<=y)return t[p].ans;
	int mid=l+r>>1,res=0;
	if(x<=mid)res=std::max(res,query(p*2,l,mid,x,y));
	if(y>mid)res=std::max(res,query(p*2+1,mid+1,r,x,y));
	return res;
}
int main(){
// 	freopen("match.in","r",stdin),freopen("match.out","w",stdout);
	std::ios::sync_with_stdio(false);std::cin.tie(0),std::cout.tie(0);
	n=read();
	for(int i=1;i<=n*5;++i){
		int x=read();v_a[x].push_back(i);
	}
	for(int i=1;i<=n;++i)std::reverse(v_a[i].begin(),v_a[i].end());
	n*=5;
	int ans=0;
	for(int i=1;i<=n;++i){
		int x=read();
		for(int y:v_a[x]){
			f[y]=std::max(f[y],query(1,1,n,1,y-1)+1);
			change(1,1,n,y,f[y]);
			ans=std::max(ans,f[y]);
		}
	}
	std::cout<<ans<<'\n';
}
posted @ 2024-06-06 20:20  Ishar-zdl  阅读(46)  评论(3)    收藏  举报