• hpu18级第一次训练赛


    A - Cotree
    题目链接:https://vjudge.net/contest/341543#problem/A
    要使连接之后的那个值最小就要找两棵树的重心.
    先来补一下树的重心:
    定义:
    找到一个点,其所有的子树中最大的子树节点数最少,那么这个点就是这棵树的重心,删去重心后,生成的多棵树尽可能平衡
    性质:
    (一)
    树中所有点到某个点的距离和中,到重心的距离和是最小的;如果有两个重心,那么他们的距离和一样。

    (二)
    把两个树通过一条边相连得到一个新的树,那么新的树的重心在连接原来两个树的重心的路径上。

    (三)
    把一个树添加或删除一个叶子,那么它的重心最多只移动一条边的距离。

    所以连接重心后求得的答案最小.

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    using namespace std;
    const int maxn=1e5+100;
    struct node
    {
    	int to,next;
    }ed[maxn*2];
    int head[maxn],cnt=0;
    void add(int u,int v)
    {
    	ed[cnt].to=v;
    	ed[cnt].next=head[u];
    	head[u]=cnt++;
    }
    bool vis[maxn];
    int dfs(int x)//遍历两棵树,求两棵树的节点数
    {
    	int res=0;
    	for(int i=head[x];i!=-1;i=ed[i].next)
    	{
    		int dx=ed[i].to;
    		if(!vis[dx]) 
    		{
    			vis[dx]=1;
    			res+=dfs(dx);
    		}
    	}
    	return res+1;
    }
    int n,nn,mm,mins,n1,n2;
    int dfs1(int u,int pre,int n)//求两棵树的重心,pre可以当做u的父节点
    {
    	int sum=0,mx=0;
    	for(int i=head[u];i!=-1;i=ed[i].next)
    	{
    		int v=ed[i].to;
    		if(v!=pre)
    		{
    			int t=dfs1(v,u,n);//这个点子树的节点数
    			sum+=t;//子树节点数之和
    			mx=max(t,mx);
    		}
    	}
    	int x=sum;
    	sum=max(n-sum-1,sum);//节点来的那个方向也是一颗子树,所以求节点两边的最大子树的节点数
    	if(sum<mins) //最小的sum的那个点就是重心
    	{
    		mm=u;
    		mins=sum;
    	}
    	return x+1;//返回这个节点所有子树节点和,包括自身
    }
    long long ans=0;//保存结果
    int  dfs2(int u,int pre)
    {
    	int res=1;
    	for(int i=head[u];i!=-1;i=ed[i].next)
    	{
    		int v=ed[i].to;
    		if(v!=pre)
    		{
    			int t=dfs2(v,u);
    			ans+=(long long)(t)*(n-t);//每条边两端节点数相乘就是这条边被用的次数,注意爆int
    			res+=t;//子树的节点和
    		}
    	}
    	return res;
    }
    int main()
    {
    	memset(head,-1,sizeof head);
    	int x,y;
    	scanf("%d",&n);
    	for(int i=0;i<n-2;i++)
    	{
    		scanf("%d%d",&x,&y);
    		add(x,y);
    		add(y,x);
    	}
    	memset(vis,0,sizeof vis);
    	int s1,s2;
    	for(int i=1;i<n;i++)
    		if(!vis[i])
    		{
    			if(i==1)
    			{
    				n1=dfs(i);
    				s1=i;
    			}
    			else
    			{
    				s2=i;
    				n2=dfs(i);
    			}
    		}
    	mins=0x3f3f3f3f;
    	dfs1(s1,-1,n1);//求两棵树的重心
    	int g1=mm;
    	mins=0x3f3f3f3f;
    	dfs1(s2,-1,n2);
    	int g2=mm;
    	add(g1,g2);//把重心连接
    	add(g2,g1);
    	dfs2(1,-1);
    	printf("%lld
    ",ans);
    	return 0;
    }
    

    D - Wave
    题目链接:https://vjudge.net/contest/341543#problem/D
    题意:定义 波为 至少有两个元素的字符串的奇数位和偶数位分别是相同的,而且奇偶位不相同,求给定序列的子序列是波的最大长度
    思路:开一个二维dp数组,dp [ i ] [ j ] 表示奇数位是i 偶数位是j的波的长度,全部初始化为0;
    遍历一遍字符串,假设当前字符是a,这个字符可以组成两种波,分别是dp[ a ] [ x ]和dp [ x ][ a ](x为非a小于c的任意数字),当dp[ a ][ x ]为偶数时,a可以填到这个波的奇数位;同理,当dp[ x ][ a ]为奇数时a可填到偶数位,其他情况不能添加就不用更新dp值了。

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    int dp[200][200],s[100010];
    int main()
    {
    	int n,c;
    	scanf("%d %d",&n,&c);
    	memset(dp,0,sizeof dp);
    	for(int i=0;i<n;i++)
    	{
    		scanf("%d",&s[i]);
    		for(int j=1;j<=c;j++)
    		{
    			if(j==s[i]) continue;
    			if(dp[s[i]][j]%2==0) 
    				dp[s[i]][j]++;
    			if(dp[j][s[i]]&1) 
    				dp[j][s[i]]++;	
    		}
    		
    	}
    	int ans=0;
    	for(int i=1;i<=c;i++)
    		for(int j=1;j<=c;j++)
    		{
    			if(j==i) continue;
    			ans=max(ans,dp[i][j]);
    		}
    	cout<<ans<<endl;
    	return 0;
     } 
    

    F - String
    题目链接:https://vjudge.net/contest/341543#problem/F

    ans=num[‘a’]*num[‘v’]*num[‘i’]*num[‘n’]/pow(n,4);

    #include<iostream>
    #include<map>
    #include<algorithm>
    
    using namespace std;
    map<char,int>ma;
    
    int main(){
    	int n;
    	string s;
    	cin>>n>>s;
    	for(int i=0;i<n;i++){
    		ma[s[i]]++;
    	}
    	int a=ma['a'],b=ma['v'],c=ma['i'],d=ma['n'];
    	int ans,res;
    	ans=a*b*c*d;
    	res=n*n*n*n;
    	int temp=__gcd(ans,res);
    	if(ans==0)
    		printf("%d/%d
    ",ans,1);
    	else printf("%d/%d
    ",ans/temp,res/temp);  //注意要约分                                                                                                                                                                      
    	
    	return 0;
    }
    

    G - Traffic
    题目链接:https://vjudge.net/contest/341543#problem/G

    这道题好坑,题意看错好久,当有车通过时间相同时,南北方向的要让路,而且是所有南北的车都要等待!!!看懂题意后暴力即可

    #include<bits/stdc++.h>
    #include<algorithm>
    #include<cmath>
    #include<cstring>
    using namespace std;
    typedef  long long ll;
    int main()
    {
    	int n,m;
    	while(~scanf("%d%d",&n,&m))
    	{
    		int a[2000],b[2000],c[5000];
    		memset(c,0,sizeof c);
    		for(int i=1;i<=n;i++)
    		{
    			scanf("%d",&a[i]);
    		}
    		for(int i=1;i<=m;i++)
    		{
    			scanf("%d",&b[i]);
    		}
    		sort(a,a+n);
    		sort(b,b+m);
    		int x=b[1],i=1;
    		while(i<=m)
    		{
    			int j=upper_bound(a,a+n,b[i])-a;
    			if((a[j-1]==b[i]&&j>1)||(j==n&&b[i]==a[j]))
    			{
    				for(int k=1;k<=m;k++)
    					b[k]++;
    				i=1;
    			}
    			else
    				i++;
    		}
    		printf("%d
    ",b[1]-x);
    	}
    	return 0;
    }```
    
    I - Budget 
    题目链接:https://vjudge.net/contest/341543#problem/I
    当做字符串输入,计算最后一位即可
    
    ```cpp
    #include<iostream>
    #include<algorithm>
    #include<cmath>
    #include<cstring>
    using namespace std;
    typedef unsigned long long ull;
    int main()
    {
    	char s[50];
    	int n;
    	while(~scanf("%d",&n))
    	{
    		double res=0;
    		for(int k=0;k<n;k++)
    		{
    			scanf("%s",s);
    			int len=strlen(s);
    			for(int i=0;i<len;i++)
    			{
    				if(s[i]=='.')
    				{
    					if(s[i+3]>='5')
    						res+=(0.01-(s[i+3]-'0')*1.0/1000);
    					else
    						res+=(0-(s[i+3]-'0')*1.0/1000);
    					break;
    				}
    			}
    		}
    		printf("%.3lf
    ",res);
    	}
    	return 0;
    }
    	
    

    J - Worker
    题目链接:https://vjudge.net/contest/341543#problem/J

    计算n个数的最小公倍数,这个数就是所有仓库人数相等的最小数,计算所有仓库需要的人数,如果能被m整除,就输出yes,否则输出no

    #include<iostream>
    #include<algorithm>
    #include<cstring>
    using namespace std;
    typedef long long ll;
    
    int main()
    {
    	int n,s[2000],num[20];
    	ll m;
    	while(~scanf("%d %lld",&n,&m))
    	{
    		memset(num,0,sizeof num);
    		for(int i=0;i<n;i++)
    		{
    			scanf("%d",&s[i]);
    			num[s[i]]++;
    		}
    		int ans=s[0];
    		int res=s[0];
    		for(int i=1;i<=10;i++)
    			if(num[i])
    			{
    				res=__gcd(ans,i);
    				ans=ans*i;
    				ans/=res;
    			}
    		res=0;
    		for(int i=1;i<=10;i++)
    			if(num[i])
    				res+=(ans/i*num[i]);
    		if(m%res==0)
    		{
    			puts("Yes");
    			for(int i=0;i<n;i++)
    				if(i==n-1)
    					printf("%lld
    ",((m/res)*(ans/s[i])));
    				else	
    					printf("%lld ",((m/res)*(ans/s[i])));
    		//	puts("");
    		}
    		else
    		{
    			puts("No");
    		}
    	}
    	return 0;
    }
    

    K - Class
    题目链接:https://vjudge.net/contest/341543#problem/K

    #include<iostream>
    using namespace std;
    
    int main()
    {
    	int x,y,a,b;
    	cin>>x>>y;
    	a=(x+y)/2;
    	b=(x-y)/2;
    	cout<<a*b<<endl;//不加换行就PE
    	return 0;
    }
    
  • 相关阅读:
    css3 font-face
    快速理解RequireJs
    移动HTML5前端性能优化指南
    HTML中head头结构
    JS面向对象基础讲解(工厂模式、构造函数模式、原型模式、混合模式、动态原型模)
    巧妙使用CSS媒体查询(Media Queries)和JavaScript判断浏览器设备类型的好方法
    关于浏览器内核与javascript引擎的一些小知识
    SVG 与 Canvas:如何选择
    NodeJS、NPM安装配置步骤(windows版本)
    ie10 css hack 条件注释等兼容方式整理
  • 原文地址:https://www.cnblogs.com/neflibata/p/12871809.html
Copyright © 2020-2023  润新知