zoukankan      html  css  js  c++  java
  • 自嗨测试赛4

    简单的树叶

    设根节点答案为 (x),假设节点上操作为 (min),则要求相邻子节点权值都大于等于 (x),假设操作为 (max),则相邻子节点权值有 (1) 个大于等于 (x) 即可,这样我们会发现,如果一个 (x) 足够大,那我们必须能够按照这样的操作,在一些叶子节点中放入足够的大于等于 (x) 的数。

    因为我们要让根节点最大,所以可以看作由根节点出发,找出所有必须大于等于 (x) 的叶子,给它们分别填上最大的数,只要使这些叶子的总个数 (cnt) 最小即可,答案就是 (k-cnt+1)。我们要求根节点能到达的最小叶子数,发现限制数量的是 (max) 操作,所以我们对于一个是 (max) 操作的点,从其儿子中选出一个能到达叶子数最小的即可,而 (min) 操作的点可以到达所有儿子的叶子。

    (f[i]) 表示 (i) 最少能到达的叶子个数

    (f[i]=sum_{jin son(i)}f[j])(i)(min) 操作

    (f[i]=min_{jin son(i)}f[j])(i)(max) 操作

    (f[i]=1)(i) 是叶子

    最终答案即为 (k-f[1]+1),复杂度 (O(n)),期望得分 (100)

    Code
    #include <cstdio>
    #include <algorithm>
    using namespace std;
    
    const int maxn=3e5+10;
    int n,cnt,k,a[maxn],head[maxn];
    struct Edge{
    	int to,nxt;
    }e[maxn*2];
    
    void add(int x,int y){
    	e[++cnt]=(Edge){y,head[x]},head[x]=cnt;
    }
    
    int dfs(int x){
    	if(!head[x]) return ++k,1;
    	int mn=1e9,sum=0;
    	for(int i=head[x];i;i=e[i].nxt){
    		int tmp=dfs(e[i].to);
    		mn=min(mn,tmp);
    		sum+=tmp;
    	}
    	return a[x]?mn:sum;
    }
    
    int main(){
    	freopen("leaf.in","r",stdin);
    	freopen("leaf.out","w",stdout);
    	scanf("%d",&n);
    	for(int i=1;i<=n;++i) scanf("%d",&a[i]);
    	for(int i=2;i<=n;++i){
    		int x;scanf("%d",&x);
    		add(x,i);
    	}
    	int tmp=dfs(1);
    	printf("%d
    ",k-tmp+1);
    	return 0;
    }
    

    老姚的服装

    预处理f[i][j]表示i,j作为左上角能向右下拓展的最大正方形边长,然后对于每个点i,j,可以O(1)求出以该点作为左上角能产生的最大答案是多少,假设答案为ans,我们就进行g[ans][i][j]++,最后对于每个ans,做一个二维前缀和

    对于询问,我们二分一个值len,表示四分之一正方形的边长,若(x1,y1)到 ((x2-len*2+1,y2-len*2+1)) 中有能作为左上角的,且最大答案为len的点,那么l=mid+1,否则r=mid-1

    判断是否存在,因为已经对g数组后两维做了二维前缀和,直接差分判即可

    Code
    
    
    #include <cmath>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    
    int n,m,q,f[505][505],g[255][505][505];
    char s[505][505];
    
    int main(){
    	freopen("clothes.in","r",stdin);
    	freopen("clothes.out","w",stdout);
    	scanf("%d%d%d",&n,&m,&q);
    	for(int i=1;i<=n;++i) scanf("%s",s[i]+1);
    	for(int i=n;i>=1;--i)
    		for(int j=m;j>=1;--j){
    			f[i][j]=1;
    			if(s[i][j]==s[i+1][j]&&s[i][j]==s[i][j+1]&&s[i][j]==s[i+1][j+1])
    				f[i][j]+=min(f[i+1][j],min(f[i][j+1],f[i+1][j+1]));
    		}
    	for(int i=1;i<=n;++i)
    		for(int j=1;j<=m;++j){
    			int len=f[i][j];
    			if(s[i][j]!='B' || i+len*2-1>n || j+len*2-1>m) continue;
    			if(f[i+len][j]!=len || s[i+len][j]!='P') continue;
    			if(f[i][j+len]!=len || s[i][j+len]!='W') continue;
    			if(f[i+len][j+len]<len || s[i+len][j+len]!='G') continue;
    			g[len][i][j]++;
    		}
    	for(int i=0;i<=250;++i)
    		for(int j=1;j<=n;++j)
    			for(int k=1;k<=m;++k)
    				g[i][j][k]+=g[i][j-1][k]+g[i][j][k-1]-g[i][j-1][k-1];
    	for(int i=1;i<=q;++i){
    		int x,y,xx,yy;scanf("%d%d%d%d",&x,&y,&xx,&yy);
    		if(x>xx) swap(x,xx);
    		if(y>yy) swap(y,yy);
    		int l=1,r=min((xx-x+1)/2,(yy-y+1)/2),mid;
    		while(l<=r){
    			mid=(l+r)/2;
    			int rx=xx-mid*2+1,ry=yy-mid*2+1;
    			if(g[mid][rx][ry]-g[mid][rx][y-1]-g[mid][x-1][ry]+g[mid][x-1][y-1]) l=mid+1;
    			else r=mid-1;
    		}
    		printf("%d
    ",r*r*4);
    	}
    	return 0;
    }
    
    

    Shawk的游戏

    最终答案一定可以表示成将一个主干放在第一层,其他的小分叉放在第二层。

    我们就去枚举每个点作为第一层,如果周围不能放在第二层的点超过2个,那么不合法,直接输No

    考虑什么样的点不能放在第二层,设枚举x在主干上,对于邻接点y

    • 度数大于3的

    • 度数为3的且除x以外任一儿子后面有分叉的

    • 度数为2的且除x以外的儿子后面有分叉的

    现在我们考虑如何判分叉,一种方法是从所有的叶子开始,将所有相邻的度数小于等于2的点都删去(标记),如果有没删的点,那一定是分叉点,

    然后我们对于每个点开一个数组c,c[x]为其所有相邻的点的vis标记之和,意思就是周围有几个儿子及后面没有分叉(也就是周围连了几条链)

    现在我们可以判分叉了,然后对于每个点求出周围不能放第二层的点的个数,如果个数大于2,肯定不合法,否则合法

    Code
    #include <cmath>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    
    const int maxn=1e5+10;
    int n,cnt,c[maxn],d[maxn],head[maxn];
    bool vis[maxn];
    struct Edge{
    	int to,nxt;
    }e[maxn*2];
    
    void add(int x,int y){
    	e[++cnt]=(Edge){y,head[x]},head[x]=cnt;
    }
    
    void del_chain(int x){
    	vis[x]=1;
    	for(int i=head[x];i;i=e[i].nxt)
    		if(!vis[e[i].to]&&d[e[i].to]<=2) del_chain(e[i].to);
    }
    
    int main(){
    	freopen("sgame.in","r",stdin);
    	freopen("sgame.out","w",stdout);
    	while(scanf("%d",&n)!=EOF){
    		memset(head,0,sizeof(head));
    		memset(vis,0,sizeof(vis));
    		memset(c,0,sizeof(c));
    		memset(d,0,sizeof(d));
    		cnt=0;
    		for(int i=1;i<n;++i){
    			int x,y;scanf("%d%d",&x,&y);
    			add(x,y),add(y,x);
    			++d[x],++d[y];
    		}
    		for(int i=1;i<=n;++i)
    			if(d[i]==1&&!vis[i]) del_chain(i);
    		for(int x=1;x<=n;++x)
    			for(int i=head[x];i;i=e[i].nxt) c[x]+=vis[e[i].to];
    		bool can=1;
    		for(int x=1;x<=n;++x){
    			int cc=0;
    			for(int i=head[x];i;i=e[i].nxt){
    				int y=e[i].to;
    				if(d[y]>3 || (d[y]==3&&c[y]-vis[x]<2) || (d[y]==2&&c[y]-vis[x]<1)) ++cc;
    			}
    			if(cc>=3){
    				can=0;
    				break;
    			}
    		}
    		puts(can?"Yes":"No");
    	}
    	return 0;
    }
    
  • 相关阅读:
    JAVA AES加密算法实现代码
    JAVA BASE64 加密解密实现代码
    eclipseLuna (4.4.0) 安装velocity 插件
    NIO中的Buffer
    Oracle死锁处理
    DWR、Comet4j在Nginx+Tomcat组合下的优化
    网站已运行时间代码
    常用DB2命令
    DB2分页查询简单示例
    comet4j推送 405/500 JSON转换异常
  • 原文地址:https://www.cnblogs.com/Lour688/p/14518177.html
Copyright © 2011-2022 走看看