2020ICPC区域赛南京站

发布时间 2023-09-21 11:56:36作者: value0

2020ICPC区域赛南京站

K Co-prime Permutation

解题思路:

首先,根据样例2不难发现,\(k\)的下界为\(1\),因为1和排列中的任何数都会互质。

其次,我们考虑下上界大概是多少,也就是\(k = n\)是否一定合法。

假设,我们有一个初识排列\(p_i = i\).此时我们有\(1\)个元素和他的下标互质。

根据经验,我们将升序排列的元素向左错位一个偏移量就会得到\(p_1 = 2,p_2 = 3,...,p_n = 1\).此时,有\(n\)个元素和下标互质。

如果我们要恰好\(k\)个元素和下标互质,那么我们将前\(k\)个数看作一个环,同时向左错位一个偏移量即可。

注意,\(k=1\)的情况要特判。该情况上面也已经讨论过。

代码:

#include<bits/stdc++.h>
using namespace std;
using ll = long long;

ll gcd(ll a,ll b)
{
	return b ? gcd(b,a %b): a;
}

void solve()
{
	int n,k;
	scanf("%d %d",&n,&k);
	if(k == 0)
	{
		puts("-1");
	}
	else if(k == 1)
	{
		for(int i = 1;i<=n;i++)
		{
			printf("%d ",i);
		}
	}
	else
	{
		vector<int> a(n + 1);
		int cnt = 2;
		for(int i = 1;i<=k;i++)
		{
			a[i] = cnt ++;
			if(cnt > k)
			{
				cnt = 1;
			}
		}
		for(int i = k + 1;i<=n;i++)
		{
			a[i] = i;
		}
		cnt = 0;
		for(int i = 1;i<=n;i++)
		{
			printf("%d ",a[i]);
		}
	}
}

int main()
{
	int t = 1;
	while(t--)
	{
		solve();
	}
	return 0;
}

L Let's Play Curling

解题思路:

稍微写一下样例,不难发现,能对答案产生贡献的红球之间没有一个蓝球。

所以,本题能够转化为,没两蓝球之间的最大红球个数。

排序后,双指针遍历即可。

代码:

#include<bits/stdc++.h>
using namespace std;
using ll = long long;
int n,m;
void solve()
{
	
	scanf("%d %d",&n,&m);
	vector<int> a(n + 1),b(m + 1);
	unordered_map<int,int> q;
	for(int i = 1;i<=n;i++)
	{
		scanf("%d",&a[i]);
		q[a[i]] ++;
	}
	for(int i = 1;i<=m;i++)
	{
		scanf("%d",&b[i]);
	}
	sort(a.begin() + 1,a.end());
	sort(b.begin() + 1,b.end());
	a.erase(unique(a.begin() + 1,a.end()),a.end());
	b.erase(unique(b.begin() + 1,b.end()),b.end());
	int i = 1;
	int j = 1;
	ll ans = 0;
	n = a.size() - 1;
	m = b.size() - 1;
//	for(int i = 1;i<=n;i++)
//	{
//		cout<<a[i]<<' ';
//	}
//	cout<<endl;
//	for(int i= 1;i<=m;i++)
//	{
//		cout<<b[i]<<' ';
//	}
//	cout<<endl;
	while(i <= n && j <= m)
	{
		ll cnt = 0;
		while(j <= m && b[j] <= a[i])
		{
			if(a[i] == b[j])
			{
				i ++;
				j ++;
			}
			else
			{
				j ++;
			}
		}
		if(j > m)
		{
			break;
		}
		while(i <= n && a[i] <= b[j])
		{
//			cout<<i<<' '<<a[i]<<endl;
			if(a[i] == b[j])
			{
				i ++;
				j ++;
				ans = max(ans,cnt);
				cnt = 0;
				continue;
			}
			else
			{
				cnt += q[a[i]];
				i ++;
				
			}
			
		}
//		cout<<i<<' '<<j<<' '<<cnt<<endl;
		ans = max(ans,cnt);
	}
	ll sum = 0;
	while(i <= n)
	{
		sum += q[a[i]];
		i ++;
	}
	ans = max(sum,ans);
	if(ans == 0)
	{
		puts("Impossible");
	}
	else
	{
		printf("%lld\n",ans);
	}
}

int main()
{
	int t = 1;
	scanf("%d",&t);
	while(t--)
	{
		solve();
	}
	return 0;
}

E. Evil Coordinate

解题思路:

如果障碍出现在出发点或者终点,那么一定会碰到障碍。

我们一共有两个维度移动方向,上下和左右。

如果我们只能在一个维度移动,并且障碍出现在起点到终点的线段上,那么一定会碰到障碍。

除此之外,我们都能避开他。

举例:

若移动序列为\(DDUUUUU\),明显终点在\((0,3)\),若障碍设置在\((0,1)\),那一定会经过。但如果障碍设置在\((0,-1)\),我们完全可以先走完上,再走下。

若我们能在两个维度移动,那我们一定能走出两条除了终点和起点外完全不相交的路径。此时,如果障碍会出现在其中一个上,我们走另一条路径必然可以避开障碍。