• Codeforces Round #544 (Div. 3)


    A - Middle of the Contest

    题意:给出两个时间,保证在同一天,求中间时刻

    思路:直接转换为一天的第多少分钟,求平均,再转换回小时:分钟的形式。

    int t,n,m;
    char buffer[10];
    void init(){}
    int main(){
    	init();
    	int t1,t2;
    	scanf("%s",&buffer[0]);
    	buffer[0]-='0';
    	buffer[1]-='0';
    	buffer[3]-='0';
    	buffer[4]-='0';
    	t1=(buffer[0]*10+buffer[1])*60+(buffer[3]*10+buffer[4]);
    	
    	scanf("%s",&buffer[0]);
    	buffer[0]-='0';
    	buffer[1]-='0';
    	buffer[3]-='0';
    	buffer[4]-='0';
    	t2=(buffer[0]*10+buffer[1])*60+(buffer[3]*10+buffer[4]);
    
    	t1=(t1+t2)/2;
    	buffer[0]='0'+(t1/60)/10;
    	buffer[1]='0'+(t1/60)%10;
    	buffer[3]='0'+(t1%60)/10;
    	buffer[4]='0'+(t1%60)%10;
    	printf("%s",buffer);
    	return 0;
    }
    

    B - Preparation for International Women's Day

    题意:给 (n) 盒子,每个盒子有 (d_{i}) 个物品。对这些盒子两两配对,问最多有多少个盒子可以参与两两配对,满足两盒子中物品相加为 (k) 的倍数。

    思路:将盒子内物品对 (k) 取模,若满足取模后的数相加为 (k) ,则配对后正好为 (k) 的倍数。然后循环看每个余数的 (i)(k-i) 的最小值,就是当前余数的最大匹配的数量。注意对(k/2)(0) 进行特判。

    int num[105];//num[i]表示余数i出现的次数。
    int t,n,m,k,tp;
    
    int main(){
    	scanf("%d%d",&n,&k);
    	for(int i=0;i<n;i++){
    		scanf("%d",&tp);
    		num[tp%k]++;
    	}	
    	int ans=num[0]/2;
    	for(int i=1;i<=k/2;i++){
    		if(i!=k-i)ans+=min(num[i],num[k-i]);
    		else ans+=num[i]/2;
    	}
    	printf("%d",ans*2);
    	return 0;
    }
    

    C - Balanced Team

    题意:给出 (n) 个人,每个人有各自的能力值 (a_{i}) ,现在要在 (i) 个中取尽量多的人构成一组,并且组内人最大能力值与最小能力值之差应不大于5,问组内人数最多是多少。

    思路:

    方法1:先对能力值进行排序,然后用双指针尺取。左指针枚举组内最低人的能力,右指针指向相对左指针来说,能取到的最高的人。

    方法2:用map记录每一个能力值出现的人的次数,然后枚举每一个最低能力值,对每一个能力值 (a_{i}) ,求出(mp[a_{i}]+mp[a_{i+1}]+mp[a_{i+2}]+mp[a_{i+3}]+mp[a_{i+4}]+mp[a_{i+5}])的值,并求出最值。

    unordered_map<int,int> mp;
    int t,n,m;
    ll tp;
    std::vector<int> stu;
    void init(){}
    int main(){
    	init();
    	scanf("%d",&n);
    	for(int i=0;i<n;i++){
    		scanf("%lld",&tp);
    		if(mp[tp]==0)stu.push_back(tp);//每个能力值最后只求一次
    		mp[tp]++;
    	}
    	ll ans=0;
    	for(int i=0;i<stu.size();i++){
    		tp=0;
    		for(int j=0;j<=5;j++){
    			tp+=mp[stu[i]+j];
    		}
    		ans=max(ans,tp);
    	}
    	printf("%lld
    ",ans);
    	return 0;
    }
    

    D - Zero Quantity Maximization

    题意:

    ​ 给出 (a_{i})(b_{i}) ,找到一个实数 (d) (注意不一定是整数),使得由 (a_{i},b_{i}) ,用 公式(c_{i}=a_{i}cdot d + b_{i}) 生成出的数组(c_{i}) 中,(c_{i} = 0) 的数量最多。

    思路:

    ​ 首先可由原式得当 (d=-frac{b_{i}}{a_{i}}) 时,(c_{i}=0) 。故,我们可以求出所有的 (frac {b_{i}} {a_{i}}) 值,统计出这些值中出现最多的那个值,则当(d) 等于出现次数最多的那个值时,满足(d=-frac{b_{i}}{a_{i}}) 式的(a_{i},b_{i}) 最多,则 (c_{i}) 中 0 最多。由于每个分数可以唯一表示为最简分数,所以我们可以统计 (<frac{b_{i}}{gcd(a,b)},frac{a_{i}}{gcd(a,b)}>) 二元组来统计 (frac {b_{i}} {a_{i}}),也可以用(b_{i}cdot 1e^9+a_{i})的单个longlong整数来统计。特别注意,对a=0,b=0需要特殊处理。当(a=0)(b=0) 时,无论 (d) 如何取值都满足,应当直接加入答案。当(a eq0)(b = 0) 时,d无论取何值都不满足。当(a eq0)(b=0)时,(b)无论是何值,都是等价的,应当统计对应成同一个(d)

    ll t,n,m;
    
    ll gcd(ll a,ll b){
        return a%b==0? b:gcd(b,a%b);
    }
    struct xy{
    	ll up,down;
    
    };
    map <pair<ll,ll>,ll> mp;
    void init(){}
    ll a[maxn],b[maxn],up[maxn],down[maxn];
    int main(){
    	init();
    	scanf("%lld",&n);
    	for(ll i=0;i<n;i++){
    		scanf("%lld",&a[i]);
    	}
    	for(ll i=0;i<n;i++){
    		scanf("%lld",&b[i]);
    	}
    	ll ans=0,maxx=0;
    	for(ll i=0;i<n;i++){
    		pair<ll,ll> tp;
    		if(a[i]==0&&b[i]==0){
    			ans++;
    			continue;
    		}
    		if(b[i]==0){
    			tp.first=0;
    			tp.second=1;
    			maxx=max(maxx,++mp[tp]);
    			continue;
    		}
    		if(a[i]==0){
    			continue;
    		}
    		ll ggcd=gcd(b[i],a[i]);
    		tp.first=b[i]/ggcd;
    		tp.second=a[i]/ggcd;
    		maxx=max(maxx,++mp[tp]);
    	}
    	printf("%lld
    ",ans+maxx);
    	return 0;
    }
    

    E - K Balanced Teams

    题意:给出n个人,每个人有能力 (a_{i}) ,现在要选出一部分人分成至多 (k) 组,要求组内人的能力值只差小于等于 (5) ,问最多能将多少人划分为组内。

    思路:二维dp,(dp[i][j]) 表示前 (i) 个人分了 (k) 组的情况下最多能将多少人划入组内。

    首先给能力值进行排序,再进行dp。

    转移方程为(dp[i][j]=max(dp[i-1][j],dp[i-x][j-1]),(其中x需要满足a[i-x]-a[i]le 5)) 因为对能力值排序过了,所以可以用单调队列来动态维护(dp[i-x][j-1])的值,也可以用其他方法。因为从尽量靠前转移过来,结果是最优的,所以可以只枚举从最尽量最左转移过来,维护一个左指针。因为左指针始终是单调的,即使直接扫,也能够达到O(n)的复杂度。最后找出 (i=n) 列中最大的dp值就是答案。

    const int N=5001;
    int a[N],b[N],dp[N][N],n,k;
    int main(){
        cin>>n>>k;
        for(int i=1;i<=n;i++) cin>>a[i];
        sort(a+1,a+1+n);
        for(int i=1;i<=n;i++){
            for(int j=i;j>=1;j--)
                if(a[j]>=a[i]-5)b[i]=j-1;
            for(int j=1;j<=k;j++)
                dp[i][j]=max(dp[i-1][j],dp[b[i]][j-1]+i-b[i]);
        }
        cout<<dp[n][k]<<endl;
    }
    

    F - Spanning Tree with Maximum Degree

    题意:求出原图中的一个生成树,使得该生成树中最大度数的节点的度数是所有生成树中最大的。

    思路:找出原图中度数最大的点,将这个点的所有边先全部加入生成树,保证度数最大,然后对剩下的边集求整个图的生成树。

    typedef long long ll;
    const int maxn=2e5+50;
    const int maxm=1e5+50;
    const ll inf=0x7fffffff;
    
    int fa[maxn];
    int find(int x){
        return (fa[x] == x) ? x : (fa[x] = find(fa[x]));
    }
    bool unio(int x, int y){
        int tx = find(x), ty = find(y);
        if (tx != ty) {
            fa[tx] = ty;
            return 1;
        }
        return 0;
    }
    
    std::vector< pair<int,int> > g,ans;
    
    int t,n,m;
    
    int in[maxn];
    void init(int n,int m){
    	for(int i=0;i<=n;i++){
    		fa[i]=i;
    		in[i]=0;
    	}
    }
    int main(){
    	scanf("%d%d",&n,&m);
    	init(n,m);
    	int u,v,maxx=0,maxi=0;
    	for(int i=0;i<m;i++){
    		scanf("%d%d",&u,&v);
    		g.push_back(make_pair(u,v));//图的所有边
            
            //统计度数
    		in[u]++;
    		in[v]++;
            
            //找出最大的度数的点。
    		if(in[u]>maxx){
    			maxx=in[u];
    			maxi=u;
    		}
    		if(in[v]>maxx){
    			maxx=in[v];
    			maxi=v;
    		}
    	}
    	for(int i=0;i<m;i++){
    		if(g[i].first==maxi||g[i].second==maxi){
    			if(unio(g[i].first,g[i].second))
    				ans.push_back(g[i]);
    		}//将最大的度数的点的所有边连起来。
    	}
    	for(int i=0;i<m;i++){
    		if(unio(g[i].first,g[i].second)){
    			ans.push_back(g[i]);//生下的边跑生成树连起来
    		}
    	}
    	for(int i=0;i<ans.size();i++){
    		printf("%d %d
    ",ans[i].first,ans[i].second);
    	}
    	return 0;
    }
    
  • 相关阅读:
    考研岁月
    sklearn 翻译笔记:KNeighborsClassifier
    网站不让复制的办法
    关于VMware Workstation 15 Player 虚拟机安装Windows系统却无法安装vmware tools的解决
    今天真是太傻了
    GoogleHacking相关技巧
    判断ARP欺骗
    Linux各个文件及其含义
    小白的开始—转一篇Linux系统入门的文章
    课时39.细线表格(理解)
  • 原文地址:https://www.cnblogs.com/chd-acm/p/13611353.html
Copyright © 2020-2023  润新知