【ICPC】2022济南站 E. Identical Parity | 数学

907 阅读3分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第13天,点击查看活动详情

【ICPC】2022济南站 E. Identical Parity | 数学

题目链接

Problem - E - Codeforces

题目

image.png

image.png

题目大意

定义序列的值是其中所有数字的和。

确定是否存在长度为 nn 的排列,使得该排列中所有长度为 kk 的子段的值具有相同的奇偶性。即判断是否存在长度为 nn 的排列,使得其所有长度为 kk 的子段和均为奇数,或者均为偶数。

排列的子段是该排列的连续子序列。

长度为 nn 的排列是一个序列,其中从 11nn 的每个整数恰好出现一次。

思路

让我们对该题的题意进行一定的转化。

首先我们观察题目:

确定是否存在长度为 nn 的排列,使得该排列中所有长度为 kk 的子段的值具有相同的奇偶性。

我们是关心子段和的奇偶性,不关心具体的值。所以我们可以让排列里所有的数都对 22 取模,子段和的奇偶性不会发生改变。则原题变成了:

有一个长度为 nn 的数组,在其中的 n2\lceil\frac{n}{2}\rceil 个位置上放 11,其他位置上放 00。是否存在一种放置方案使得数组中所有长度为 kk 的子段的值具有相同的奇偶性。

又因为是所有长度为 kk 的区间,我们可以看做在长度为 nn 的数组上有一个大小为 kk 的框在滑动,框一开始框住了前 kk 个元素,每往右移动一个位置,框内最左边的元素就会离开框,框外右边第一个元素就会进入框。框内元素的和奇偶性保持不变。

所以我们每移出框一个 00,就必须移入一个 00。每移出一个 11,就必须移入一个 11。即整个 0101 数组有长度为 kk 的循环节。

因为整个序列中应该有 n2\lceil\frac{n}{2}\rceil 个位置上是 11,有 n2\lfloor\frac{n}{2}\rfloor 个位置上是 00,所以我们希望每个循环节内的 0011 数量之差尽可能小,即每 kk 个元素的和是 k2\lceil\frac{k}{2}\rceil。整个数组内有恰好 nk\lfloor\frac{n}{k}\rfloor 个完整的循环,则完整的循环的和是 k2×nk\lceil\frac{k}{2}\rceil\times\lfloor\frac{n}{k}\rfloor

因为每个循环内元素的和是 k2\lceil\frac{k}{2}\rceil,所以我们希望最后剩余的 nmodkn \mod k 的子段中 00 的数量可以多一点,来弥补每个循环内少放的 00

最后长度为 n%kn \% k 的子段中 00 的数量不能超过序列长度,也不能超过完整的循环中 00 的数量,所以最多能放 00 的数量为

min(n%k,k2)\min(n\%k,\lfloor\frac{k}{2}\rfloor)

所以最后长度为 n%kn \% k 的子段中最少要放 11 的数量是

n%kmin(n%k,k2)n\% k-\min(n\% k,\lfloor\frac{k}{2}\rfloor)

所以整个数组中至少要放 11 的数量是

k2×nk+n%kmin(n%k,k2)\lceil\frac{k}{2}\rceil\times\lfloor\frac{n}{k}\rfloor+n\% k-\min(n\% k,\lfloor\frac{k}{2}\rfloor)

容易发现,只要整个数组中至少要放 11 的数量不超过 n2\lceil\frac{n}{2}\rceil,就一定可以通过调整最后的子段中 0101 的数量使得整个数组中 11 的数量恰为 n2\lceil\frac{n}{2}\rceil

综上所述,

k2×nk+n%kmin(n%k,k2)n2\lceil\frac{k}{2}\rceil\times\lfloor\frac{n}{k}\rfloor+n\% k-\min(n\% k,\lfloor\frac{k}{2}\rfloor)\le \lceil\frac{n}{2}\rceil

就输出 Yes,否则输出 No

代码

#include <bits/stdc++.h>
using namespace std;
void solve()
{
	int n, m;
	scanf("%d%d", &n, &m);
	if ((n+1)/2>=((m+1)/2)*(n/m)+n%m-min(n%m,m/2)) printf("Yes\n");
	else printf("No\n");
}

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