Codeforces Round 888 (Div. 3)补题

Escalator Conversations(Problem - A - Codeforces)

题目大意:有一个自动扶梯,共有m级台阶,每级台阶高为k,上面有n个人,我们规定如果两人站在不同的台阶上,高度恰好相同时可以进行交谈,小f身高为h,它想知道它可以和多少人进行交谈。

思路:这题没什么难度,就是小f与其他人的高度差要恰好是k的倍数,同时有两个限定条件,两人不能站在同一级台阶上,则不能与高度相同的人进行交谈,另外台阶总共m级,到第m级时就到终点了,所以倍数需要小于m。

#include
using namespace std;
int main()
{
	int t;
	scanf("%d",&t);
	while(t--)
	{
		int n,m,k,h,c=0;
		scanf("%d%d%d%d",&n,&m,&k,&h);
		for(int i=1;i<=n;i++)
		{
			int x;
			scanf("%d",&x);
			int d=abs(h-x);
			if(d&&d%k==0&&d/k

Parity Sort(Problem - B - Codeforces)

题目大意:给定一个数组a[],我们每次可以选择两个元素进行交换,需要满足两个元素的奇偶性相同,问最后能否得到一个非降序数组。

思路:这道题显然就是奇数和偶数内部进行排序,我们可以先将奇数元素分别进行排序,然后按照原数组中每个数的奇偶性往里面填,最后看看我们填好的数组是否有序即可。

#include
using namespace std;
int a[200010],b[200010];
vectorj,o;
int main()
{
	int t;
	scanf("%d",&t);
	while(t--)
	{
		int n;
		scanf("%d",&n);
		for(int i=1;i<=n;i++)
		{
			scanf("%d",&a[i]);
			if(a[i]&1) j.push_back(a[i]);
			else o.push_back(a[i]);
		}
		sort(j.begin(),j.end());
		reverse(j.begin(),j.end());
		sort(o.begin(),o.end());
		reverse(o.begin(),o.end());
		for(int i=1;i<=n;i++)
		{
			if(a[i]&1) b[i]=j.back(),j.pop_back();
			else b[i]=o.back(),o.pop_back();
		}
		int c=0,flag=0;
		for(int i=1;i<=n;i++)
		{
			if(c>b[i]) 
			{
				flag=1;
				break;
			}
			c=b[i];
		}
		if(flag) printf("NO\n");
		else printf("YES\n");
	}
}

Tiles Comeback(Problem - C - Codeforces)

题目大意:有一排瓷砖,总共n块,第i块有一个颜色ci,当前处在第1块,最后要到第n块,每次可以随意跳,产生一个路径,长度为p,p可以整除k,并且满足将p按照k块一个区域进行划分的话,可以划分出若干个区域,区域内部颜色相同,相邻区域之间颜色不一定不同,问是否存在这样的路径p。

思路:这道题看似麻烦,但是很简单,一定要把题目看清楚,相邻区域同与不同皆可。总共只有两种大的情况,开头和结尾相同,开头和结尾不同。如果开头和结尾相同,那么只要在数组中找到k个与开头相同的元素即可,结尾字符可以与找到的最后一个进行替换;如果开头和结尾不同,那么就从开头找k个,从结尾找k个,两者找到的区间不相交即可。一定要把题目看清楚。

#include
using namespace std;
int c[200010];
int main()
{
	int t;
	scanf("%d",&t);
	while(t--)
	{
		int n,k;
		scanf("%d%d",&n,&k);
		for(int i=1;i<=n;i++) scanf("%d",&c[i]);
		if(c[1]==c[n])
		{
			int i,cnt=0;
			for(i=1;i<=n;i++)
			{
				if(c[i]==c[1]) cnt++;
				if(cnt==k) break;
			}
			if(cnt==k) printf("YES\n");
			else printf("NO\n");	
		}
		else
		{
			
			int i=1,j=n,cnt=0;
			for(i=1;i<=n;i++)
			{
				if(c[i]==c[1]) cnt++;
				if(cnt==k) break;
			}
			cnt=0;
			for(j=n;j>=1;j--)
			{
				if(c[j]==c[n]) cnt++;
				if(cnt==k) break;
			}
			if(i

Prefix Permutation Sums(Problem - D - Codeforces)

题目大意:对于一个排列,我们求出其前缀和,但现在前缀和少了一位数,现在给出一个少了一位的前缀和数组,问它是否对应一个排列。

思路:少了一位前缀和,这个前缀和的位置有两种可能,一种是最后一个丢了,那么我们还原出来的只差一个数,可以直接判是,如果是前面的丢了,那么我们还原的时候,还原出来的某一位数应该是排列中的两个数相加,和可能大于n,也可能小于n,如果小于n,那么一定有一个数出现两次。所以可以用map将所有的出现的数及它的出现次数统计出来,然后遍历map,将小于等于n的数标记一下,同时在map中减掉一次,然后遍历n,找一找有几个数没被标记,同时计算出没被标记的数的和,如果是一个,那么直接输出yes,如果是两个,那么就看两个数的和是否在map中,如果大于两个,直接判否。

#include
using namespace std;
#define int long long
int st[200010];
signed main()
{
	int t;
	scanf("%lld",&t);
	while(t--)
	{
		int n;
		scanf("%lld",&n);
		int c;
		mapmp;
		for(int i=0;i2) printf("NO\n");
		else if(c==2) 
		{
			if(mp[tmp]) printf("YES\n");
			else printf("NO\n");
		}
		else printf("YES\n");
	}
}

Nastya and Potions(Problem - E - Codeforces)

题目大意:现在已知n种药水单瓶的价格,同时其中的k中药水我们已经有无限多,其中一种药水可以由多种药水混合得到,问获得每瓶药水需要多少金币。

思路:因为一瓶药水可以由一些药水获得,而这些药水又可以由另一些药水混合,所以我们可以直接对每种药水进行深搜,为了优化我们可以加个记忆化搜索,另外我们已知的是单价,所以一次只能买一瓶,不用考虑药水可以重复利用的问题。至于图如何建,我们只要在每瓶药水和可以获得它的药水之间建一条有向边即可。

#include
using namespace std;
#define int long long
int dp[200010];
int st[200010];
int h[200010],e[200010],ne[200010],idx;
void add(int a,int b)
{
	e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}
int dfs(int u)
{
	if(st[u]) return dp[u];
	st[u]=1;
	int sum=0,c=0;
	for(int i=h[u];i!=-1;i=ne[i])
	{
		int j=e[i];
		sum += dfs(j);
		c++;
	}
	if(c) dp[u]=min(dp[u],sum);
	return dp[u];
}
signed main()
{
	int t;
	scanf("%lld",&t);
	while(t--)
	{
		int n,k;
		scanf("%lld%lld",&n,&k);
		for(int i=1;i<=n;i++) scanf("%lld",&dp[i]),st[i]=0,h[i]=-1;
		for(int i=1;i<=k;i++)
		{
			int x;
			scanf("%d",&x);
			dp[x]=0;
		}
		idx=0;
		for(int i=1;i<=n;i++)
		{
			int m;
			scanf("%lld",&m);
			for(int j=1;j<=m;j++)
			{
				int x;
				scanf("%lld",&x);
				add(i,x);
			}
		}
		for(int i=1;i<=n;i++)
		{
			int res=dfs(i);
			printf("%lld ",res);
		}
		printf("\n");
	}
}

Lisa and the Martians(Problem - F - Codeforces)

题目大意:定义严格小于2^k的数为火星数字,现有n个火星数字组成的数组a[],要求从中选两个数字,并且随便找一个火星数组x,使得(a[i]^x)&(a[j]^x)最大,输出i,j,x。

思路:这里既然涉及到位运算,那么就从二进制的角度考虑,最后一步运算求得是&,所以就要使两者异或x后对应的位数中有尽可能多的相同的1,再往前推一步,那么就是要求a[i]和a[j]中要有尽可能多的位数相同。那么问题就转化成从数组中找到两个数,不对,我们要找的这个数尽可能的大,那么就是高位尽可能能的放1,那么就是两个数高位尽可能的相同。有一个贪心的思路,就是说按照非降序排列后,选出来的数应该相邻,相邻两个数比不相邻的数高位相同的概率大一点,但是这个很难证明,不过可以写。那么就可以在线性的时间复杂度内解决。

#include
using namespace std;
int main()
{
	int t;
	scanf("%d",&t);
	while(t--)
	{
		int n,k;
		scanf("%d%d",&n,&k);
		vector>c;
		for(int i=1;i<=n;i++) 
		{
			int x;
			scanf("%d",&x);
			c.push_back({x,i});
		}
		sort(c.begin(),c.end());
		int mx=-1,d=0,l,r;//mx需要为一个小于0的数,因为结果可能为0
		for(int i=0;i=0;j--)
			{
				if( (a>>j&1)==(b>>j&1) )
				{
					sum += 1<>j&1)) x += 1<mx)
			{
				mx=sum,d=x,l=c[i].second,r=c[i+1].second;
			}
		}
		printf("%d %d %d\n",l,r,d);
	}
}

 但是,这个题主要想考察的是用trie树求最大同或值。因为只有两数二进制的同一位上的数值相同,才能在结果中变成1,同1同0都是相同,所以,就是求最大同或值。这里会有相同的数出现,所以我们先查询再插入,为了保证查询结果,trie树最初需要全部初始化成0.

#include
using namespace std;
const int M=200010*32;
struct node
{
	int pos;
	int son[2];
}tree[M];
int ans,ansx,pos1,pos2;
void query(int u,int num,int bit,int cnt,int cntx,int pos)
{
	if(bit==-1)
	{
		if(cnt>ans)
		{
			ans=cnt;
			ansx=cntx;
			pos1=pos;
			pos2=tree[u].pos;
		}
		return;
	}
	int s=(num>>bit)&1;
	if(tree[u].son[s])
	{
		cnt += (1<>bit)&1;
	if(!tree[u].son[s]) tree[u].son[s]=++now;
	insert(tree[u].son[s],num,bit-1,pos);
}
int main()
{
	int t;
	scanf("%d",&t);
	while(t--)
	{
		int n,k;
		scanf("%d%d",&n,&k);
		for(int i=0;i<=n*k;i++) 
		{
			tree[i].pos=tree[i].son[0]=tree[i].son[1]=0;
		}
		now=0;
		ans=0;
		ansx=0;
		pos1=1,pos2=2;
		for(int i=1;i<=n;i++)
		{
			int x;
			scanf("%d",&x);
			query(0,x,k-1,0,0,i);
			insert(0,x,k-1,i);
		}
		printf("%d %d %d\n",pos1,pos2,ansx);
	}
}

这里初始情况要记得考虑,也就是将pos1赋成1,pos2赋成0,最小为0,可能结果就是0,那么就无法更新,所以要人为指定。tree[i].son[0]和tree[i].son[1]当中存的相当于指针,这个可以类比邻接表来看。

你可能感兴趣的:(codeforces补题,算法)