noip模拟39[还好有送分题!!呼~~]

noip模拟39 solutions

这次考试是真的难,不过第一题是真的水

然后我就只拿了185pts,还有一道题是今年noi原题

害伤心。。。。。。。。。

T1 打地鼠

这个我一眼,真的就一眼,就有了\(\mathcal{O(n^2)}\)的算法

但是我真的不敢打,因为我怕过不了

然后苦想冥想要找到一个\(\mathcal{O(nlogn)}\)的算法,

但是我看了看复杂度,觉得还好,

重要的是开考一分钟的时候,我听见全机房的键盘都在响,我就果断的开打了

AC_code
#include<bits/stdc++.h>
using namespace std;
#define re register int
const int N=2005;
int n,k;
int jz[N][N],fro[N][N],ans;
signed main(){
	scanf("%d%d",&n,&k);
	for(re i=1;i<=n;i++){
		char x[N];scanf("%s",x+1);
		for(re j=1;j<=n;j++){
			jz[i][j]=x[j]-'0';
			fro[i][j]=fro[i-1][j]+fro[i][j-1]-fro[i-1][j-1]+jz[i][j];
		}
	}
	for(re i=k;i<=n;i++)
		for(re j=k;j<=n;j++)
			ans=max(ans,fro[i][j]-fro[i-k][j]-fro[i][j-k]+fro[i-k][j-k]);
	printf("%d",ans);
}

T2 竞赛图

哦,这好象是我第一次接触到这种图吧,还是挺好理解的

就是一个无向完全图,变成有向的,就是两两之间有连边,但是是有向的而已

然鹅考场上我看出来这个了,却只拿到了40pts,仅仅是枚举点集得到的分

后来看到正解,这思路也是过于清奇了。

会发现,如果我们将所有的强连通分量进行缩点的话,我们的图会变成一个拓扑图

两个不连通的强联通分量之间只会有一种边,从其中一个向另外一个,

因为如果还有边可以回来的话,那么两个强联通分量应该是同一个分量

但是实际操作的时候并不需要缩点,我们只是借用这个思想

有了上面的基础,我们会发现,单点一定是强联通分量

那么我们可以这样向后拓展,一个强联通分量中伸出一些边连向另外一些点

那么这些点组成的集合的所有子集再并上当前的点集一定不是一个强联通分量

直接递推就好啦

AC_code
#include<bits/stdc++.h>
using namespace std;
#define re register int
const int N=25;
int T,n;
bool vis[1<<N];
int edg[1<<N],ans;
signed main(){
	scanf("%d",&T);
	while(T--){
		memset(edg,0,sizeof(edg));
		memset(vis,true,sizeof(vis));
		scanf("%d",&n);
		for(re i=1;i<=n;i++)
			for(re j=1;j<=n;j++){
				int x;scanf("%d",&x);
				edg[1<<i-1]|=(x<<j-1);
			}
		for(re i=1;i<(1<<n);i++)
			if(!edg[i])edg[i]=edg[i^(i&-i)]&edg[i&(-i)];
		for(re i=1;i<(1<<n);i++){
			if(!vis[i])continue;
			for(re j=edg[i];j;j=(j-1)&edg[i])vis[i|j]=false;
		}
		ans=0;
		for(re i=0;i<(1<<n);i++)ans+=vis[i];
		printf("%d\n",ans);
	}
}

T3 糖果

这个我是真的不会,连\(\mathcal{O(n^6)}\)的dp都没有看懂

但是最后的正解我还是略知一二

我们肯定是先放一个A,再放一个B最后放上C

我们记录每一个物品在A,B的序列中出现的位置,

AB每向后挪动一步,C就会多出来一个备选的位置,

根据这个不断转移就好了,dp完成之后,此时的C中只有\(\frac{n}{3}\)个数,再乘上几个方案就好了

我还没有改过,几乎已经放弃,不重要啦

T4 树

这个题吧,就是2021NOI T1,好像挺简单的还。。

直接用树链剖分+线段树维护,好像题解弄得还挺麻烦

直接给每一个节点赋一个时间戳,每次都要不一样,然后我们发现

这样的话,一条边两端时间戳一样就是白的,不一样就是黑的

直接线段树维护就好了

AC_code
#include<bits/stdc++.h>
using namespace std;
#define re register int
const int N=3e5+5;
int n,q;
int to[N*2],nxt[N*2],head[N],rp;
void add_edg(int x,int y){
	to[++rp]=y;
	nxt[rp]=head[x];
	head[x]=rp;
}
struct XDS{
	#define ls x<<1
	#define rs x<<1|1
	int sum[N*4],laz[N*4];
	int ln[N*4],rn[N*4];
	void pushup(int x){
		if(rn[ls]!=ln[rs])sum[x]=sum[ls]+sum[rs]+1;
		else sum[x]=sum[ls]+sum[rs];
		ln[x]=ln[ls];rn[x]=rn[rs];
		return ;
	}
	void pushdown(int x){
		if(!laz[x])return ;
		ln[ls]=rn[ls]=ln[rs]=rn[rs]=laz[x];
		laz[ls]=laz[rs]=laz[x];
		sum[ls]=sum[rs]=0;laz[x]=0;
		return ;
	}
	void build(int x,int l,int r){
		if(l==r){
			ln[x]=rn[x]=l;
			sum[x]=0;
			return ;
		}
		int mid=l+r>>1;
		build(ls,l,mid);
		build(rs,mid+1,r);
		pushup(x);return ;
	}
	void ins(int x,int l,int r,int ql,int qr,int v){
		if(ql<=l&&r<=qr){
			ln[x]=rn[x]=v;
			sum[x]=0;laz[x]=v;
			return ;
		}
		pushdown(x);
		int mid=l+r>>1;
		if(ql<=mid)ins(ls,l,mid,ql,qr,v);
		if(qr>mid)ins(rs,mid+1,r,ql,qr,v);
		pushup(x);return ;
	}
	int query(int x,int l,int r,int ql,int qr){
		//cout<<x<<" "<<l<<" "<<r<<" "<<ql<<" "<<qr<<endl;
		if(ql<=l&&r<=qr)return sum[x];
		pushdown(x);
		int mid=l+r>>1,ret=0;
		if(ql<=mid)ret+=query(ls,l,mid,ql,qr);
		if(qr>mid)ret+=query(rs,mid+1,r,ql,qr);
		//if(ql<=mid&&qr>mid&&rn[ls]!=ln[rs])ret++;
		if(ql<=mid&&qr>mid&&ln[rs]!=rn[ls])ret++;
		pushup(x);
		return ret;
	}
	int query_kin(int x,int l,int r,int pos){
		if(l==r)return ln[x];
		pushdown(x);
		int mid=l+r>>1,ret=0;
		if(pos<=mid)ret=query_kin(ls,l,mid,pos);
		else ret=query_kin(rs,mid+1,r,pos);
		pushup(x);
		return ret;
	}
	#undef ls
	#undef rs
}xds;
int siz[N],son[N],dep[N],fa[N];
void dfs_fi(int x){
	siz[x]=1;son[x]=0;
	for(re i=head[x];i;i=nxt[i]){
		int y=to[i];
		if(y==fa[x])continue;
		dep[y]=dep[x]+1;fa[y]=x;
		dfs_fi(y);siz[x]+=siz[y];
		if(!son[x]||siz[y]>siz[son[x]])son[x]=y;
	}
}
int top[N],dfn[N],cnt;
void dfs_se(int x,int f){
	top[x]=f;dfn[x]=++cnt;
	if(son[x])dfs_se(son[x],f);
	for(re i=head[x];i;i=nxt[i]){
		int y=to[i];
		if(y==fa[x]||y==son[x])continue;
		dfs_se(y,y);
	}
}
void upd(int x,int y,int v){
	while(top[x]!=top[y]){
		if(dep[top[x]]<dep[top[y]])swap(x,y);
		xds.ins(1,1,n,dfn[top[x]],dfn[x],v);
		x=fa[top[x]];
	}
	if(dep[x]<dep[y])swap(x,y);
	xds.ins(1,1,n,dfn[y],dfn[x],v);
}
int ask(int x,int y){
	int ret=0;
	while(top[x]!=top[y]){
		//cout<<dep[top[x]]<<" "<<dep[top[y]]<<" "<<x<<" "<<y<<endl;
		if(dep[top[x]]<dep[top[y]])swap(x,y);
		ret+=xds.query(1,1,n,dfn[top[x]],dfn[x]);
		int tmp1=xds.query_kin(1,1,n,dfn[top[x]]);
		int tmp2=xds.query_kin(1,1,n,dfn[fa[top[x]]]);
		if(tmp1!=tmp2)ret++;
		x=fa[top[x]];
	}
	if(dep[x]<dep[y])swap(x,y);
	ret+=xds.query(1,1,n,dfn[y],dfn[x]);
	//cout<<ret<<endl;
	return ret;
}
signed main(){
	scanf("%d",&n);
	for(re i=1;i<n;i++){
		int x,y;scanf("%d%d",&x,&y);
		add_edg(x,y);add_edg(y,x);
	}
	dfs_fi(1);dfs_se(1,1);
	xds.build(1,1,n);
	scanf("%d",&q);
	int tag=n;
	while(q--){
		int typ,x,y;
		scanf("%d%d%d",&typ,&x,&y);
		if(typ==1)++tag,upd(x,y,tag);
		else printf("%d\n",ask(x,y));
	}
}
posted @ 2021-08-20 15:00  fengwu2005  阅读(50)  评论(0编辑  收藏  举报