Codeforces Round 909 (Div. 3)

Game with Integers

题目大意:v1和v2在玩游戏,玩家得到一个整数n,在轮到她的时候,可以对整数进行加1或者减1的操作,如果v1操作后,整数能够整除3,那么她就胜利了,如果10次移动后,v1还没有胜利,那么v2就胜利了。最后v1胜利就打印"First",否则打印"Second".

思路:能整除3即模3得0,一个数模上3只有三种情况,0,1,2;如果因为v1必须要操作,所以,实际上只要这个数n%3!=0,那么v1就会胜利,否则v2只需要复原v1的操作就能使v1每次都得对3的倍数操作,进而无法得到能整除3的数。

#include<bits/stdc++.h>
using namespace std;
int main()
{
	int t;
	scanf("%d",&t);
	while(t--)
	{
	int n;
	scanf("%d",&n);
	if(n%3) printf("First\n");
	else printf("Second\n");
}
}

250 Thousand Tons of TNT

题目大意:有排成一排的n个货物,可以选择每辆车装多少个,要求每辆车装的数量一样多,同时每辆车总和的最大值和最小值的差值最大。装箱顺序为,若选择每车装x个,那么1-x装在第一辆车,x+1-2x装在第二辆车……以此类推,求出最大差值。

思路:这道题,连续一段装在一辆车,且要求和,很容易想到前缀和,那么该如何选择一车装多少个呢?实际上暴力就可,不用担心会超时,那么嵌套循环的第二层不一定会跑。

#include<bits/stdc++.h>
using namespace std;
#define int long long
int a[150010],sum[150010];
signed main()
{
	int t;
	scanf("%lld",&t);
	while(t--)
	{
		int n;
		scanf("%lld",&n);
		for(int i=1;i<=n;i++)
		{
			scanf("%lld",&a[i]);
		}
		for(int i=1;i<=n;i++) sum[i]=sum[i-1]+a[i];
		int ans=0;
		for(int i=1;i<=n-1;i++)
		{
			if(n%i==0)
			{
				int mx=0,mi=150000000000000;
				for(int j=i;j<=n;j+=i)
				//1-i在一车
				{ 
					int d=sum[j]-sum[j-i];
					mx=max(mx,d);
					mi=min(mi,d);
				}
				ans =max(ans,mx-mi);
			}
		}
		printf("%lld\n",ans);
	}
}

Yarik and Array

题目大意:给定一个数组,要求出其非空子数组和的最大值,同时还要求非空子数组中的元素必须是奇偶相间。

思路:这个就是连续子序列求最大和的变式。累加,当遇到奇偶性不符合,或者加完得到负数的时候,重置即可。另外零对总和无贡献,但是会卡奇偶性,所以如果需要以0开头,那么尽量后跳一下,同样负数也是,所以尽量不以0和负数开头。

#include<bits/stdc++.h>
using namespace std;
#define int long long
int a[200010];
signed main()
{
	int t;
	scanf("%lld",&t);
	while(t--)
	{
		int n;
		scanf("%lld",&n);
		for(int i=1;i<=n;i++) scanf("%lld",&a[i]);
		int k=1,mx=-1e9-7;;
		//全部小于等于0
		while(a[k]<=0&&k<=n) mx=max(mx,a[k]),k++;
		if(k>n) printf("%lld\n",mx);
		else if(k==n) printf("%lld\n",a[n]);
		else
		{
			int sum=a[k],c=a[k],mx=a[k];//!!!a[k]后面可能全是小于它的数
			for(int i=k+1;i<=n;i++)
			{
				if(c==-1e9-7)
				{
					sum=a[i];
					mx=max(sum,mx);
					c=a[i];
					continue;
				}
				if((c%2==0&&a[i]%2)||(c%2&&a[i]%2==0))
				{
					sum += a[i];
					if(sum<0) 
					{
						k=i;
						while(a[k]<=0&&k<=n) k++;
						i=k-1;
						sum=0;
						c=-1e9-7;
					}
					c=a[i];
					mx=max(mx,sum);
				}
				else 
				{
					k=i;
					while(a[k]<=0&&k<=n) k++;
					i=k-1;
					c=-1e9-7;
					sum=0;
				}
			}
			printf("%lld\n",mx);
		}
	}
}

Yarik and Musical Notes

题目大意:给定一个数组,数组里面的每个数ai表示的实际是2^ai,我们定义(a,b)是满足(2^a)^(2^b)=(2^b)^(2^a),问数组中有多少对ai,aj,满足i<j,(ai,aj).

思路:

所以,只有i,j,相等,或者一个为1,一个为2时才能满足。而题目给的i<j的意义不过是限制每一对不能重复计算,即换位置后不重复记录。那么我们只需要统计出每一种的数量,然后处理一下即可。k=mp[i],那么i产生的就是(k-1)*k/2, 1,2产生的就是mp[1]*mp[2].

#include<bits/stdc++.h>
using namespace std;
#define int long long
map<int,int>mp;
signed  main()
{
	int t;
	scanf("%lld",&t);
	while(t--)
	{
		int n;
		scanf("%lld",&n);
		for(int i=1;i<=n;i++)
		{
			int x;
			scanf("%lld",&x);
			mp[x]++;
		}
		int ans=0;
		for(auto it:mp)
		{
			int ti=it.second;
			ans += (ti-1)*ti/2;
		}
		ans += mp[1]*mp[2];
		cout<<ans<<endl;
		mp.clear();
	}
}

Queue Sort

题目大意:给定一个数组,我们可以进行若干次操作,每次操作将第一个数取出,放到末尾,然后去跟前面的比,如果前面的数大于它,那么就进行交换。问最少进行多少次操作可以是数组变成非递减的,如果不能使数组变成非递减的,那么就输出-1。

思路:这个题有点像冒泡排序,我们可以得到的结论就是,第一个数被取出放到后面,一定会放到一个对它来说有序的位置,或者换句话说,被操作过的数都会被放在有序的位置上,那么我们就要考虑,什么时候不能再进行操作了,很明显是最小的那个数为第一个数的时候,因为它还会被放回来,所以它后面的数也不能被操作。如果后面的数就是非递减的,那么自然无所谓,但是如果有递减存在,后面的数是无法被操作的,那么就无法使整个序列有序。所以我们只需要找到最小的数,去看它后面的数是否有递减存在即可。

#include<bits/stdc++.h>
using namespace std;
int a[200010];
int main()
{
	int t;
	scanf("%d",&t);
	while(t--)
	{
		int n;
		scanf("%d",&n);
		int idx,mi=1e9+7;
		for(int i=1;i<=n;i++)
		{
			scanf("%d",&a[i]);
			if(a[i]<mi) mi=a[i],idx=i;
		}
		int c=a[idx],flag=1;
		for(int i=idx+1;i<=n;i++)
		{
			if(c>a[i])
			{
				flag=0;
				break;
			}
			c=a[i];
		}
		if(flag) printf("%d\n",idx-1);
		else printf("-1\n");
	}
}

Alex's whims

题目大意:现有一棵树,要求是第i天,树中要有两叶子节点的距离为di,我们可以进行的操作如下:

选择u,v1,v2,u和v1有边相连,u和v2没有边相连,我们可以将u与v2连起来,同时将u和v1之间的边断掉。现在要我们自己给出一棵树,并给出关于每个di需要如何操作,打印u,v1,v2,如果不需要操作那么就打印-1,-1,-1。只要每步操作合法即可。

思路:这道题看上去非常麻烦,既要我们自己给出一棵树,对每个di,我们还要来找是否已经有合法的点,如果没有该如何操作。但是实际上,有个特别简单的思路,即将n个节点顺次接起来,以1为根节点,我们现在相当于得到了支路1。每次的距离为d,即这条路上有有d+1个点。我们以根节点1作为一个固定的叶子节点,我们来讨论普遍的三种情况:

1.支路1上的点的数量恰好等于d+1,那么就不用进行任何操作,因为从1到叶子节点刚好可以满足要求。

2.支路1上点的数量多于d+1,我们可以将末尾多的点截下来接到支路2后面。(支路2最初为空,表示支路2的数组最初只有节点2,因为1要做叶子节点,所以不能接在1后面)

3.支路1上点的数量小于d+1,那么就将差的那部分从支路2的末尾截下来接到支路1的末尾。

这样就可以满足题目的要求了。

#include<bits/stdc++.h>
using namespace std;
int main()
{
	int t;
	scanf("%d",&t);
	while(t--)
	{
		int n,m;
		scanf("%d%d",&n,&m);
		vector<int>b1,b2;
		for(int i=1;i<=n;i++) b1.push_back(i);
		b2.push_back(2);
		for(int i=1;i<n;i++) printf("%d %d\n",i,i+1);
		while(m--)
		{
			int d;//距离d
			scanf("%d",&d);
			d++;
			if(d==b1.size())
			{
				printf("-1 -1 -1\n");
			}
			else if(d<b1.size())
			{
				d = b1.size()-d;
				//将b1多的接在b2
				int v2=b2.back();
				vector<int>q;
				int u;
				for(int i=0;i<d;i++)
				{
					u=*b1.rbegin();
					q.push_back(*b1.rbegin());
					b1.pop_back();
				}
				int v1=b1.back();
				cout<<u<<' '<<v1<<' '<<v2<<endl;
				for(int i=q.size()-1;i>=0;i--)
				{
					b2.push_back(q[i]);
				}
			}
			else
			{
				d =d-b1.size();
				
				int v2=b1.back();
				vector<int>q;
				int u;
				for(int i=0;i<d;i++)
				{
					u=*b2.rbegin();
					q.push_back(*b2.rbegin());
					b2.pop_back();
				}
				int v1=b2.back();
				cout<<u<<' '<<v1<<' '<<v2<<endl;
				for(int i=q.size()-1;i>=0;i--)
				{
					b1.push_back(q[i]);
				}
			}
		}
	}
}

  • 23
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值