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;
}
posted @ 2022-03-12 13:05  Aireen_Ye  阅读(31)  评论(0编辑  收藏  举报
底部 顶部 留言板 归档 标签
Der Erfolg kommt nicht zu dir, du musst auf den Erfolg zugehen.