[codefoces2017-2018 ACM-ICPC]刷题小练

本文精选了算法竞赛中的多项挑战题目,并提供了详细的题解思路与实现代码,涵盖链表构造、序列划分、括号配对、贪心策略等多个方面。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

比赛题目

博主有了一群边缘OB翻译者,做题顺利了好多,这次提供翻译啦(感谢OB们

翻译:

A:输入一个数n,接下来n行:每行两个数li ri,代表当前情况下节点i的前驱和后继,没有则为0;求一种连法使得其形成1整条链表,其中只出现1~n,输出n行,每行两个数li ri,代表节点i的前驱和后继

B:Ivan有一个长度为n的、元素为各不相同的整数的数组,他决定使用Merge Sort,所以他决定将所有元素拆成多个递增的数列,求最少数列分法,输出时每行一个数列

C:给予你2个数n,k,要求你使用n对括号使得其权值和为k
*对于一对括号(),其权值为其外包裹它的()个数
输出合法的括号序列,若无正解,输出Impossible
补充:C题的样例解释:
1、 3对括号得到1,输出()(()),和为0+0+1
2、 4对括号得到6,输出(((()))),和为0+1+2+3
3、 2对括号得到5,无法得到正确的答案,所以输出Impossible

D:求狗最多吃的食物碗数。
输入:第一行2个数n,T,T代表狗有T的时间吃,第T秒时狗将不能吃东西。
第二行n个数ti,表示第i碗食物将在ti时冷却。
狗将从初始位置0开始,第i碗食物在i的位置,狗需要消耗1秒从x跑向x+1,对于第i碗食物,有:
若到达时时间已经>=ti,则狗将直接吃掉食物并跑向右侧的碗
若到达时间<ti,则狗有2个选择:等待到ti吃掉这碗食物再跑向下一个碗,或者选择直接跑向下一个碗;
若狗在T前跑过n个碗,则时间直接结束。

E:对于一个1*N的空间内,每个格子上可能有一只Packman、或一颗豆子,或什么都没有。Packman每个时间点都可以向任意方向移动一格并吃掉这格上的豆子(如果有的话),同一时间内同一格上可以有任意只数Packman朝向任意方向;求最短时间使得所有豆子被吃光并输出这个时间

F题:有n个候选人竞争k个位置,其中有m个给他们投票的人,每个人最后的排名按照他们的得票数从高到低排列,如果有两个人得票数量相同,则按照最后投给他票的人投票时间从早到晚进行排列
前k个人可以入选,然后现在有a个人已经投票 你需要对每个人进行判断:后面的m-a个人投完票以后若他一定能入选,输出1,若他有可能入选 输出2,若他不能入选,输出3
样例:第一行分别是nkma
下面一行a个数表示前a个人投给了谁

G:sb题请看样例自行理解。

H:给数列中的数加总和尽量少的数字使其先递增后递减(光增也资瓷)

J:
学生间要送礼物,对于一个学生,ta只会向他认识的学生送礼物。
输入:第一行n,m,接下来m行每行2个数xi,yi,表示xi,yi中间已经认识;如果xi,yi出现过,仍会出现yi,xi
输出:第一行一个数x,是最倒霉的学生送出的礼物个数,要求这个x尽可能小.(spj,满足x正确的情况下任意解均可)
接下来m行,每行2个数x,y,表示x要向y送1个礼物
补充:最倒霉的学生是送出礼物最多的学生

K:
给定n次条乘车路线,每次从地点a->地点b,乘车路线按时间给出(即要按顺序处理)
每次乘车要花费a 当第i+1条路线的起点与第i条的终点重合时,可以选择换乘,则花费降为b
还可以购买不超过k张旅行卡,使得在两站之间的往返不需要花费.
求跑完所有路线的最小花费,注意区分大小写

L题,给定一颗有N个点的树,对于每个节点,已知由它发出的每条边连接哪些节点,要求复原这颗树

M题给一个数列,判断是不是等差数列,输出下一项

题解:

博主只做了其中的6道水题,多多海涵

A题代码:

#include <cstdio>
#include <iostream>
using namespace std;
int n,i,pre[105],nxt[105],kq[105],num;
int main()
{
	scanf("%d",&n);
	for (i=1;i<=n;i++)
	{
		scanf("%d%d",&pre[i],&nxt[i]);
		if (pre[i]==0) kq[++num]=i;
	}
	for (i=1;pre[i];i=pre[i]);
  	int ll=i;
  	for (i=ll;num;i=nxt[i])
  	  if (nxt[i]==0)
  	  {
  	  	if (kq[num]==ll) num--;
  	  	if (num) nxt[i]=kq[num],pre[kq[num]]=i,num--;
	  }
  	for (i=1;i<=n;i++)
	  printf("%d %d\n",pre[i],nxt[i]);  
}

啊这个B题有必要说一下,毕竟naive的博主一开始使用了n^2logn的愚蠢子序列做法,但是其实可以nlogn的,这里使用了vector,因为ta既然已经新增加了一个序列,这个数字一定小于上一个序列的最大值啊(上一个序列里的最大值是所有序列最大值中最小的!maxx递减啊)。如果ta不小于的话,由于maxx数组是递减的,我们就可以二分出ta在哪个组里啦

B题代码:

#include <cstdio>
#include <cstring>
#include <iostream>
#include <vector>
using namespace std;
int a[200005],g[200005],maxx[200005];
vector<int>q[200005];
bool c[200005];
void stupid()
{
	int n,i,j;int maxx=0,lj=0;
	scanf("%d",&n);
	lj=n;
	for (i=1;i<=n;i++) scanf("%d",&a[i]);
	for (i=1;lj && i<=n;i++)
	  if (!c[i])
	  {
	  	for (j=1;j<=maxx;j++) g[j]=0;
	  	maxx=0;
	  	for (j=i;lj && j<=n;j++)
	  	  if (!c[j])
	  	  {
	  		int l=1,r=maxx;
		    while (l<=r)
		    {
		    	int mid=(l+r)>>1;
		    	if (g[mid]>a[j]) r=mid-1;
				else l=mid+1;   
			}
			if (maxx<r+1)
			  maxx=r+1,g[r+1]=a[j],printf("%d ",a[j]),c[j]=true,lj--;
		  }
	  	printf("\n");
	  }
}
int main()
{
	int n,i,j;
	scanf("%d",&n);
	for (i=1;i<=n;i++) scanf("%d",&a[i]);
	int zu=1;maxx[zu]=a[1];q[zu].push_back(a[1]);
	for (i=2;i<=n;i++)
	  if (maxx[zu]>a[i])
	  {
	  	maxx[++zu]=a[i];
	  	q[zu].push_back(a[i]);
	  }
	  else
	  {
	  	int l=1,r=zu;
	  	while (l<=r)
	  	{
	  		int mid=(l+r)>>1;
	  		if (maxx[mid]<a[i]) r=mid-1; 
			else l=mid+1;
		}
		maxx[r+1]=a[i];
		q[r+1].push_back(a[i]);
	  }
	for (i=1;i<=zu;i++)
	{
		for (j=0;j<q[i].size();j++) printf("%d ",q[i][j]);
		printf("\n");
	}
}

C题代码:

#include <cstdio>
using namespace std;
long long k;
int main()
{
	long long n;
	scanf("%I64d%I64d",&n,&k);
	if (n*(n-1)/2<k){printf("Impossible"); return 0;}
	long long cnt=1;
	while (k)
	{
		if (cnt-1<=k)
		{
			printf("(");
			k-=cnt-1;
			cnt++; n--;
		}
		else{printf(")"); cnt--;}
	}
	while (cnt!=1) printf(")"),cnt--;
	while (n) printf("()"),n--;
}


D题还是很有意思的:

为什么我只寻找最大的等饭时间?因为我等了ta其他的饭都等完了。即使ta在一些小时间的后面,我等小时间也相当于等着大时间啊(其他详见注释

#include <cstdio>
#include <queue>
#include <iostream>
using namespace std;
priority_queue <int> q;
int main()
{
	int n,T;
	scanf("%d%d",&n,&T);
	int x,tp=T-1,dl=0,ans=0;//tp=T-1:还有从0-1的时间
	for (int i=1;i<=min(n,T-1);i++)
	{
		tp--;//还剩下多少时间,每次减去的时间用来奔跑,放在开始就减的目的:第t时间你就不能吃了哦 
		while (!q.empty() && q.top()>tp) q.pop(),tp--;//如果剩下的时间不够等饭就t出去,因为max值已经记下,所以ta发挥的最大水平已经记录 
		scanf("%d",&x);x-=i;//还要等几分钟啊 
		if (x<=tp) q.push(x),dl++;//还来得及,那就等着试试 
		ans=max(dl,ans);
	}
	printf("%d",ans); 
}


G题代码:
#include <cstdio>
#include <iostream>
using namespace std;
int cnt[10];char st[10];
int main()
{
	int n,i,j;
	scanf("%d",&n);
	for (i=1;i<=n;i++)
	{
		scanf("%s",st);
		for (j=0;j<7;j++)
		  if (st[j]=='1') cnt[j]++;
	}
	int ans=0;
	for (i=0;i<7;i++) ans=max(ans,cnt[i]);
	printf("%d",ans);
}

H题代码(莫队乱搞?注意1-n都有可能是最高哦):

#include <cstdio>
#include <iostream>
#define N 100005
#define LL long long
using namespace std;
int a[N],mq[N];
int main()
{
	int n,i,r,l;
	scanf("%d",&n);
	if (n==1){printf("0");return 0;}
	for (i=1;i<=n;i++) scanf("%d",&a[i]),mq[i]=a[i];
	for (i=n;i>=1;i--) 
	  mq[i]=max(mq[i+1]+1,a[i]);
	mq[1]=max(mq[2]+1,max(mq[1],a[0]+1));
	LL now=0,ans=0;
	for (i=n;i>=1;i--) 
	  now+=mq[i]-a[i];	ans=now;
	for (i=2;i<=n;i++)
	{
		now-=mq[i-1];
		mq[i-1]=max(mq[i-2]+1,a[i-1]); 
		now+=mq[i-1];
		now-=mq[i];
		mq[i]=max(max(mq[i+1]+1,a[i]),mq[i-1]+1); 
		now+=mq[i];
		ans=min(ans,now);
    }
	printf("%lld",ans);  
}

M题代码:

#include <cstdio>
using namespace std;
int n,i,a[105],ans;
int main()
{
	bool fff=true;
	scanf("%d",&n);scanf("%d",&a[1]);
	for (i=2;i<=n;i++)
	{
		scanf("%d",&a[i]);
		if (!ans) ans=a[i]-a[i-1];
		else if (ans!=a[i]-a[i-1]) fff=false;
	}
	if (fff) printf("%d",a[n]+ans);
	else printf("%d",a[n]);  
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值