2019JXCPC重现赛(未完待续)

Cotree

题意:有两棵树,一共n个点,在两棵树上连一条边,使得他们变成一棵树,问如何连边使得他们题目中的式子最小。

思路:树中所有点到某个点的距离和中,到重心的距离和最小,先求得重心,然后求连接重心后节点的两两距离和即可。 摘自

 

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int inf=0x3f3f3f3f;
const int maxn=1e5+5;
const int maxm=3e5+5;
struct edge{
	int u,v,next;
}e[maxm];
int head[maxn],cnt;
void addedge(int u,int v){
	e[cnt].u=u;
	e[cnt].v=v;
	e[cnt].next=head[u];
	head[u]=cnt++;
}
int n,vis[maxn],tot,p,minnum;
void dfs0(int u){
	if(vis[u])
		return;
	vis[u]=1;
	tot++;
	for(int i=head[u];i!=-1;i=e[i].next)
		dfs0(e[i].v);			
}
int dfs1(int u,int pre,int N){
	int sum=0,max_sub=0;
	for(int i=head[u];i!=-1;i=e[i].next){
		int v=e[i].v;
		if(v==pre)
			continue;
		int t=dfs1(v,u,N);
		max_sub=max(max_sub,t);
		sum+=t;
	}
	max_sub=max(max_sub,N-sum-1);
	if(max_sub<minnum){
		minnum=max_sub;
		p=u;
	}
	return sum+1;
}
ll ans=0;
int dfs2(int u,int pre){
	int sum=0;
	for(int i=head[u];i!=-1;i=e[i].next){
		int v=e[i].v;
		if(v==pre)
			continue;
		int t=dfs2(v,u);
		ans+=1ll*t*(n-t);
		sum+=t;
	}
	return sum+1;
}
int main(){
	memset(head,-1,sizeof(head));
	cnt=0;
	scanf("%d",&n);
	for(int i=1;i<=n-2;i++){
		int u,v;
		scanf("%d%d",&u,&v);
		addedge(u,v);
		addedge(v,u);
	}
	int s1,s2,n1,n2;
	for(int i=1;i<=n;i++){
		if(!vis[i]){
			tot=0;
			dfs0(i);
			if(i==1){
				s1=i;
				n1=tot;
			}
			else{
				s2=i;
				n2=tot;
			}
		}
	}
	int g1,g2;
	minnum=inf;
	dfs1(s1,-1,n1);
	g1=p;
	minnum=inf;
	dfs1(s2,-1,n2);
	g2=p;
	addedge(g1,g2);
	addedge(g2,g1);
	ans=0;
	dfs2(1,-1);
	printf("%lld\n",ans);
	return 0;
}

 Wave

题意:构造一个序列,使得奇数位置上的数完全一样,并且偶数上的也一样,奇数上的和偶数上的数不同,求该序列的最长长度。 

思路:枚举两个数。  

#include<bits/stdc++.h>
using namespace std;
int a[100005];
typedef pair<int,int> p;
vector<p> cnt[105];
int cmp(p x,p y){
	return x.second<y.second;
}
int main(){
	int n,c;
	while(~scanf("%d%d",&n,&c)){
		memset(cnt,0,sizeof(cnt));
		int x;
		for(int i=1;i<=n;i++){
			scanf("%d",&a[i]);
			cnt[a[i]].push_back({a[i],i});
		}
		int mx=0;
		for(int i=1;i<=c;i++){
			for(int j=i+1;j<=c;j++){
				if(cnt[i].size()&&cnt[j].size()){
					vector<p>v;
					for(int k=0;k<cnt[i].size();k++)
						v.push_back(cnt[i][k]);
					for(int k=0;k<cnt[j].size();k++)
						v.push_back(cnt[j][k]);
					sort(v.begin(),v.end(),cmp);
					int f,s=0;
					for(int k=0;k<v.size();k++){
						if(!k)
							s++,f=v[k].first;
						else if(v[k].first!=f)
							s++,f=v[k].first;
					}
					mx=max(s,mx);
				}
			}
		}
		printf("%d\n",mx);
	}
}

String

题意:给定长度为n的字符串,问任选4个能组成avin的概率

思路:分母为n^4,分子根据乘法原理的求得。 

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int a[30];
char s[205];
int main(){
	int n;
	while(~scanf("%d",&n)){
		memset(a,0,sizeof(a));
		scanf("%s",s);
		for(int i=0;i<n;i++)
			a[s[i]-'a']++;
		int s1=a['a'-'a'],s2=a['v'-'a'],s3=a['i'-'a'],s4=a['n'-'a'];
		int t1=n*n*n*n;
		int sum=s1*s2*s3*s4;
		if(sum==0){
			printf("0/1\n");
			continue;
		}
		int t=__gcd(sum,t1);
		sum/=t,t1/=t;
		printf("%d/%d\n",sum,t1);
	}
	return 0;
}

 Traffic

题意:东西和南北方向有车子通过,问推迟最少的时间使得两个方向的车子不会相撞。

思路:枚举可能相撞的x,取使得不会相撞的最少值

#include<bits/stdc++.h>
using namespace std;
int a[1005],b[1005],vis[1000005];
int main(){
	int n,m;
	while(~scanf("%d%d",&n,&m)){
		memset(vis,0,sizeof(vis));
		for(int i=0;i<n;i++)
			scanf("%d",&a[i]);
		for(int i=0;i<m;i++)
			scanf("%d",&b[i]);
		for(int i=0;i<n;i++)
			for(int j=0;j<m;j++)
				if(a[i]>=b[j])
					vis[a[i]-b[j]]=1;
		for(int i=0;;i++)
			if(!vis[i]){
				printf("%d\n",i);
				break;
			}
	}
	return 0;
}

 Rng

题意:在区间里选择两个区间,问区间相交的概率。

 思路:可以通过求出区间不想交的概率求出相交的概率,假设区间长度为0,先选第一个线段的右端点有n种可能,再选第二个线段的左端点,有(n-1)种可能,重复算了两次,所以概率为1-(n*(n-1))/(2*n*n)

#include<bits/stdc++.h>
using namespace std;
const int mod=1e9+7;
typedef long long ll;
ll inv(ll b){return b==1?1:(mod-mod/b)*inv(mod%b)%mod;}
int main(){
	ll n;
	while(~scanf("%lld",&n)){
		printf("%lld\n",(n+1)*inv(2*n)%mod);
	}
}

Budget 

题意:四舍五入第3位小数,问丢失了多少精度

#include<bits/stdc++.h>
using namespace std;
double a[1005];
char s[30];
int main(){
	int n;
	while(~scanf("%d",&n)){
		double s1=0,s2=0;
		int sum=0;
		for(int i=0;i<n;i++){
			scanf("%s",s);
			int l=strlen(s);
			if(s[l-1]-'0'>=5)
				sum+=10-(s[l-1]-'0');
			else sum-=(s[l-1]-'0');
		}
		printf("%.3lf\n",(double)sum/1000.0);
		
	}
}

Worker

题意:问能否分配工人使得每个仓库的工作量相同。

思路:求的所以数的最小公倍数即可。 

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll a[1005],b[1005];
int main(){
	int n;
	ll m;
	while(~scanf("%d%lld",&n,&m)){
		a[0]=0;
		for(int i=1;i<=n;i++)
			scanf("%lld",&a[i]),b[i]=a[i];
		for(int i=1;i<=n;i++){
			if(i!=1){
				a[i]=a[i]/__gcd(a[i],a[i-1])*a[i-1];
			}
		}
		ll sum=0;
		for(int i=1;i<=n;i++)
			sum+=a[n]/b[i];
		if(m%sum==0&&m>=sum){
			printf("Yes\n");
			for(int i=1;i<=n-1;i++)
				printf("%lld ",m/sum*(a[n]/b[i]));
			printf("%lld\n",m/sum*(a[n]/b[n]));
		}
			
		else printf("No\n");
	}
}

 Class

签到题

#include<bits/stdc++.h>
using namespace std;
int main(){
	int x,y;
	while(~scanf("%d%d",&x,&y)){
		int a=(x+y)/2,b=(x-y)/2;
		printf("%d\n",a*b);
	}
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值