(Training 15)Codeforces Round #688

A. Cancel the Trains

思路:相撞的时候会在对角线相撞 那么统计对角线即可

#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=1e5+10;
bool st[N];
int main(){
	int T;
	cin>>T;
	while(T--){
		memset(st,0,sizeof st);
		int n,m;
		cin>>n>>m;
		for(int i=1;i<=n;i++){
			int x;
			scanf("%d",&x);
			st[x]=1;
		}
		int res=0;
		for(int i=1;i<=m;i++){
			int x;
			scanf("%d",&x);
			if(st[x])res++;
		}
		cout<<res<<endl;
		
	}
	return 0;
}

B. Suffix Operations

和前天的D很想 要是提前写了这个题 那么上大分了
思路:我从前往后统计出总和以后
分别从第一个到最后一个进行枚举求出min即为答案

#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=2e5+10;
typedef long long LL;
LL a[N];
int main(){
	int T;
	cin>>T;
	while(T--){
		int n;
		scanf("%d",&n);
		for(int i=1;i<=n;i++){
			scanf("%lld",&a[i]);
		}
		LL ans=0,maxv=0;
		for(int i=2;i<=n;i++){
			ans+=max(a[i]-a[i-1],a[i-1]-a[i]);
		}
		if(n>=2){
			maxv=max(a[2]-a[1],a[1]-a[2]);
			maxv=max(maxv,max(a[n]-a[n-1],a[n-1]-a[n]));
		}
		for(int i=2;i<=n-1;i++){
			maxv=max(maxv,-max(a[i+1]-a[i-1],a[i-1]-a[i+1])+max(a[i+1]-a[i],a[i]-a[i+1])+max(a[i-1]-a[i],a[i]-a[i-1]));
		}
		printf("%lld\n",ans-maxv);
	}
	return 0;
}

C. Triangles

题意:给出0-9数字的举行 问能形成最大的三角形
思路:枚举每一个点进行统计0-9数字中每一个数字的minx maxx maxy miny
然后再一次枚举进行统计答案 取max

#include<iostream>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
const int N=2e3+10;
char g[N][N];
int minx[10],maxx[10],miny[10],maxy[10],ans[10];
int main(){
	int T;
	scanf("%d",&T);
	while(T--){
		int n;
		scanf("%d",&n);
		for(int i=1;i<=n;i++)
		scanf("%s",g[i]+1);
		for(int i=0;i<=9;i++)minx[i]=miny[i]=n,maxx[i]=maxy[i]=0,ans[i]=0;;
		for(int i=1;i<=n;i++)
			for(int j=1;j<=n;j++){
				int x=g[i][j]-'0';
				minx[x]=min(i,minx[x]);
				maxx[x]=max(i,maxx[x]);
				miny[x]=min(j,miny[x]);
				maxy[x]=max(j,maxy[x]);
			}
		for(int i=1;i<=n;i++)
			for(int j=1;j<=n;j++){
				int x=g[i][j]-'0';
				ans[x]=max(ans[x],max(max(i-minx[x],maxx[x]-i)*max(n-j,j-1),max(j-miny[x],maxy[x]-j)*max(n-i,i-1)));
			}
		for(int i=0;i<=9;i++)
		printf("%d ",ans[i]);
		puts("");
	}
	return 0;
}

D. Checkpoints

一个比较有趣的构造题 因为每一位都只能是偶数 不可能生产奇数 那么首先判断如果输入的是奇数那么输出-1
否则均可以通过构造生产 这里我们预处理出63种情况
通过二分来 减去find这个值后 直到为0 构造出游戏关卡

#include<iostream>
#include<cstring>
#include<algorithm>
#include<unordered_map>
#include<vector>
using namespace std;
typedef long long LL;
const int N=1e2+10;
LL f[N];
int main(){	
	for(int i=1;i<=63;i++)f[i]+=f[i-1]*2+2;
	int T;
	cin>>T;
	while(T--){
		LL n;
		cin>>n;
		if(n&1)puts("-1");
		else{
			vector<int>ans;
			while(n){
				int pos=upper_bound(f+1,f+1+63,n)-(f+1);
				n-=f[pos];
				ans.push_back(1);
				for(int i=1;i<pos;i++)
				ans.push_back(0);
			}
			printf("%d\n",ans.size());
			for(int t:ans)
			printf("%d ",t);
			puts("");
		}
	}
}

E. Dog Snacks在这里插入图片描述

题意:狗狗从1节点出发 他能寻找到距离他k内位置的食物 并沿着路径一直走 他走最优的情况下把整个地图全部吃完食物 最后全部吃完后并回到1点的位置也要小于等于k 求出k最小是多少
思路:一个很有意思的树形dp
考虑状态 我们递归返回的是
遍历完遍历一个节点他所有的子树后
返回到父亲所需要的最小距离k
即从子树返回到父亲所需要的最小k
如果该节点是叶子节 必然有k=1
如果该节点有多个子树那必然是即最短的子树的k+1
我们考虑了从子树返回到父亲后所返回的状态
这时候ans均取k的最大值

但这还是不够的我们只考虑的父亲和儿子的转移
但没有考虑儿子之间的转移
我们接着分析 一个节点中 几个子树的转移
从子树中转移到另一个子树 k最大必然是最深的子树的k+1
如果这个点是根节点1
那么最深的子树不需要转移到别的节点 只需要回到根节点
但是次大子树有可能和最大子树相等
那么这时候我们取ans取max(k,`k+1)

在所有的k的取值中我们取max即为最终结果

#include<iostream>
#include<cstring>
#include<vector>
#include<algorithm>
using namespace std;
const int N=2e5+10;
struct Edge{
	int v,next;
}edge[N<<1];
int head[N],tot,degree[N],ans,T;
void init(){
	memset(head,0,sizeof head);
	tot=0;
	memset(degree,0,sizeof degree);
	ans=0;
}
void add(int u,int  v){
	edge[++tot]={v,head[u]};
	head[u]=tot;
}
int dfs(int u,int fa){
	if(degree[u]==1&&u!=1)return 1;//一个叶子节点 
	vector<int>tmp;
	for(int i=head[u];i;i=edge[i].next){
		int v=edge[i].v;
		if(v!=fa){
			tmp.push_back(dfs(v,u));//能访问完子树的最小K 子树返回不做考虑 
		}
	}
	sort(tmp.begin(),tmp.end());//最大的到最小的距离 
	if(tmp.size()>1){
		if(u==1)ans=max({ans,tmp.back(),tmp[tmp.size()-2]+1});
		//是根节点那么从次长子树+1转移到最长子树的花费 或者最长子树最大长度 
		else  ans=max(ans,tmp.back()+1);//不是根节点 回到父亲的最短路径 
	}
	else ans=max(ans,tmp[0]);//只有一个子树 
	return tmp[0]+1;//能访问完子树的最小K 子树返回不做考虑 
}
int main(){
	scanf("%d",&T);
	while(T--){
		init();
		int n;
		scanf("%d",&n);
		for(int i=1;i<n;i++){
			int u,v;
			scanf("%d%d",&u,&v);
			add(u,v);
			add(v,u);
			degree[u]++;
			degree[v]++;
		}
		dfs(1,1);
		printf("%d\n",ans);
	}
	return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值