• ICPC2020济南


    C

    Description

    给定n个堆,每个堆的石子个数在[1,3],合并两个堆(大小分别为x,y)的代价为(x mod 3)(y mod 3)。求合并成一堆的最小代价。

    Solution

    显然如果堆的大小是3的倍数时,无论怎么合并,对代价的贡献都是0。
    所以可以直接忽略大小为3的倍数的堆,考虑mod 3=1,2的堆。
    显然,合并(1,2)直接可以获得一个3的倍数,所以尽可能合并(1,2).
    对于剩下来的1/2,三个一组合并,又可以得到一个3的倍数。然后对最后剩下的堆直接合并即可。

    #include<bits/stdc++.h>
    using namespace std;
    int t[5],ans;
    int main(){
    	for(int i=1;i<=3;++i)
    		scanf("%d",&t[i%3]);
    	if(t[1]&&t[2]){
    		int tmp=min(t[1],t[2]);
    		ans+=2*tmp;
    		t[1]-=tmp;t[2]-=tmp;t[0]+=tmp;
    	}
    	if(t[1]>1){
    		int tmp=t[1]/3;
    		ans+=3*tmp;
    		t[1]%=3;
    		t[0]+=tmp;
    		if(t[1]>1) ans+=1; 
    	} 
    	if(t[2]>1){
    		int tmp=t[2]/3;
    		ans+=6*tmp;
    		t[2]%=3;
    		t[0]+=tmp;
    		if(t[2]>1) ans+=4;
    	}
    	printf("%d\n",ans); 
    	return 0;
    }
    

    D

    Description

    每个学生的作业的字数范围在\([l_i,r_i]\),每个学生的得分与他的字数在班上的排名有关,越多排名越高。
    设学生的初始排名为大家都写\(r_i\)个字的情况下的排名,求在排名不变差的情况下的最小总字数。

    Solution

    初始排名按\(r_i\)排序即可得到。
    对于一个学生,只需要不比 所有排名不比他高的人 写得少即可。
    即取max{ max{ 排名比他低的人能接受的最少字数 },max{ 排名和他相同的人的\(l_i\) } }。
    那么按\(r_i\)从小到达扫一遍确定每个人能接受的最少字数即可。

    #include<bits/stdc++.h>
    using namespace std;
    const int N=100005;
    struct student{
    	int l,r;
    }a[N]; 
    int n;
    long long ans;
    bool cmp(student a,student b){
    	if(a.r!=b.r) return a.r<b.r;
    	return a.l>b.l;
    }
    int main(){
    	scanf("%d",&n);
    	for(int i=1;i<=n;++i)
    		scanf("%d%d",&a[i].l,&a[i].r);
    	sort(a+1,a+1+n,cmp);
    	for(int i=1,l=0;i<=n;++i){
    		if(a[i].r!=a[i-1].r)
    			l=max(l,a[i].l);
    		ans+=l;
    	}
    	printf("%lld\n",ans);
    	return 0;
    } 
    

    G

    Description

    给定两个数x,y(x>y),每次可以将x异或上一个不大于当前x的数。求一种小于五步的方案使x变成y。

    Solution

    很显然,将x异或到当前位数的全1状态所需的数<x(因为所需的数在当前x的位数下最高位是0,所以必然<x),那么我们先将x变成位数不变的全1态。
    然后我们只需异或一个与y的0/1相反的数即可。显然这个数小于全1态。

    #include<bits/stdc++.h>
    using namespace std;
    long long x,y,ans;
    int main(){
    	scanf("%lld%lld",&x,&y);
    	printf("2\n");
    	for(int i=0;(1ll<<i)<=x;++i){
    		if(!((1ll<<i)&x)) ans|=(1ll<<i); 
    	}
    	printf("%lld ",ans);
    	ans=0ll;
    	for(int i=0;(1ll<<i)<=x;++i){
    		if(!((1ll<<i)&y)) ans|=(1ll<<i); 
    	}
    	printf("%lld\n",ans);
    	return 0;
    } 
    

    J

    Description

    给定一棵树,求一种给每个点赋值\(a_i\)的方案使得存在一条边(x,y)的充要条件是\(a_x\;or\;a_y=2^{60}-1\)

    Solution

    构造题。
    观察可以发现层数同奇偶的层之间必不连。那么可以对奇偶层设置不同的后缀01/10来保证同奇偶的层之间不连。
    可以证明的是,min{奇数层节点个数,偶数层节点个数} \(\leq\frac{n}{2}\)
    所以我们可以对个数少的那个部分用二进制某位x取0来进行连边约束:只有能连向该点的节点的二进制位x取1。
    这样就可以保证连边之间\(a_x\;or\;a_y=2^{60}-1\),不连的点之间\(a_x\;or\;a_y<2^{60}-1\)

    #include<bits/stdc++.h>
    using namespace std;
    const int N=105;
    struct graph{
    	int nxt,to;
    }e[N<<1];
    int g[N],dep[N],n,cnt,tot=2;
    long long ans[N];
    void adde(int x,int y){
    	e[++cnt].nxt=g[x];g[x]=cnt;e[cnt].to=y;
    }
    void dfs(int u){
    	if(dep[u]&1) ++cnt;
    	ans[u]=(1<<(dep[u]&1));
    	for(int i=g[u];i;i=e[i].nxt)
    		if(!dep[e[i].to]){
    			dep[e[i].to]=dep[u]+1;
    			dfs(e[i].to);
    		}
    }
    void dfs1(int u,bool flag){
    	if(flag){
    		++tot;
    		ans[u]|=((1ll<<60)-1ll-(1ll<<tot)-3);
    	}
    	for(int i=g[u];i;i=e[i].nxt)
    		if(dep[e[i].to]>dep[u]){
    			dfs1(e[i].to,!flag);
    		}
    }
    void dfs2(int u,bool flag){
    	if(!flag){
    		long long tmp=0;
    		for(int i=g[u];i;i=e[i].nxt)
    			tmp|=(((1ll<<60)-1ll)^ans[e[i].to]);
    		tmp-=(tmp&3);
    		ans[u]|=tmp;
    	}
    	for(int i=g[u];i;i=e[i].nxt)
    		if(dep[e[i].to]>dep[u]){
    			dfs2(e[i].to,!flag);
    		}
    }
    int main(){
    	scanf("%d",&n);
    	for(int i=1,x,y;i<n;++i){
    		scanf("%d%d",&x,&y);
    		adde(x,y);adde(y,x);
    	}
    	cnt=0;dep[1]=1;dfs(1);
    	if(cnt<=(n>>1)){
    		dfs1(1,true);
    		dfs2(1,true);
    	}
    	else{
    		dfs1(1,false);
    		dfs2(1,false);
    	}
    	
    	for(int i=1;i<=n;++i)
    		printf("%lld ",ans[i]);
    	return 0;
    }
    

    M

    Description

    经典小学烙饼问题。有n个饼,每个饼的两面都要烙,可以同时烙k个。求最少需要烙几个饼。

    Solution

    先把所有的第一面烙了,再烙第二面。然后最后一批第一面可能会剩位置给最早烙好的第一面。

    #include<bits/stdc++.h>
    using namespace std;
    int main(){
    	int n,k;
    	scanf("%d%d",&n,&k);
    	int fro=n,back=0;
    	int ans=0;
    	ans+=fro/k;back+=fro/k*k;fro%=k;
    	++ans;back-=min(back,k-fro);back+=fro;fro=0;
    	ans+=back/k;back%=k;
    	if(back) ++ans;
    	printf("%d\n",ans);
    	return 0;
    }
    
  • 相关阅读:
    Less(27a)GET
    Less(27)GET
    虚拟机打开文件黑屏
    mysql开放远程连接权限
    fidder如何设置代理转发
    如何获取APK的包名
    ADB调试原理之通俗版本
    adb端口5037被占用怎么办
    ADB调试原理
    如何使用无线调试手机
  • 原文地址:https://www.cnblogs.com/AireenYe/p/ICPC2020Jinan.html
Copyright © 2020-2023  润新知