LGR-130】洛谷 2 月月赛 I & KDOI Round 4

P9033 「KDOI-04」XOR Sum

思路

  1. 易得, 0 xor ⁡ 0 … xor ⁡ 0 = 0 0\operatorname{xor}0\dots\operatorname {xor}0=0 0xor0xor0=0,本题主要运用这一性质。
  2. k ≤ m k\le m km 时,可以先输出 n − 1 n-1 n1 0 0 0,然后输出 1 1 1 k k k
  3. k > m k>m k>m 时,尝试 k k k 分解为多个 2 2 2 的某次幂的异或和。如,若 k k k 14 14 14,则其二进制表达是 ( 1110 ) 2 (1110)_2 (1110)2,可以分解为 ( 1000 ) 2 xor ⁡   ( 100 ) 2 xor ⁡   ( 10 ) 2 (1000)_2\operatorname {xor}\ (100)_2\operatorname {xor}\ (10)_2 (1000)2xor (100)2xor (10)2。易得,某个方案是否合理取决于 max ⁡ { a i } \max\{a_i\} max{ai},显然如此分解最容易合理。若这种方式分解得到的最大项仍大于 m m m,则说明不存在合理的方案。
  4. 记分解完后得到的项数为 p p p。若 p ≤ n p\le n pn,则在输出这些项后,需要再输出 n − p n-p np 0 0 0;若 p > n p>n p>n,则根据贪心,需要把前 p − n + 1 p-n+1 pn+1 项合并得到 s u m sum sum,如果 s u m > m sum>m sum>m 则输出 − 1 -1 1,否则输出 s u m sum sum 后再输出分解后得到的其他项。
  5. 最坏时间复杂度为 O ( T n ) \mathcal O(Tn) O(Tn)

代码

#include <bits/stdc++.h>
using namespace std;
int t, n, m, k;
const int maxn = 2e5 + 100;
void read (int &x) 
{
	int w = 1; x = 0;
	char ch = getchar ();
	while (ch < '0' || ch > '9') 
	{
		if (ch == '-') w = -1;
		ch = getchar ();
	}
	while (ch >= '0' && ch <= '9') 
	{
		x = (x << 1) + (x << 3) + ch - 48;
		ch = getchar ();
	}
	x *= w;
}
int main ()
{
	read (t);
	while (t --) 
	{
		read (n), read (k), read (m);
		int p = 0, a[maxn];
		if (k <= m) 
		{
			for (int i = 1; i < n; i++) 
				printf ("0 ");
			printf ("%d\n", k);
		}
		else 
		{
			int flag = 0;
			while (k != 0) 
			{
				if ((k & -k) > m) 
				{
					flag = 1;
					break;
				}
				a[++ p] = (k & -k);
				k ^= (k &-k);
			}
			if (flag) 
			{
				printf ("-1\n");
				continue;
			}
			if (p <= n) 
			{
				for (int i = 1; i <= p; i++)
					printf ("%d ", a[i]);
				for (int i = 1; i <= n - p; i++)
					printf ("0 ");
				printf ("\n");
			}
			else 
			{
				int pi = 1, sum = 0, cur = p;
				while (cur > n - 1) 
				{
					sum += a[pi ++], cur --;
					if (sum > m) 
					{
						flag = 1;
						break;
					}
				}
				if (flag) 
				{
					printf ("-1\n");
					break;
				}
				printf ("%d ", sum);
				for (int i = pi; i <= p; i++)
					printf ("%d ", a[i]);
				printf ("\n");		
			}
		}
	}
	return 0;
}

P9034 「KDOI-04」Again Counting Set

思路

  1. Mex ⁡ ( S ) \operatorname{Mex}(S) Mex(S) 作为讨论依据
  2. Mex ⁡ ( S ) = 0 \operatorname{Mex}(S)=0 Mex(S)=0 时,由 ∏ x ∈ S x = min ⁡ x ∈ S { x } \prod\limits_{x\in S}x=\min\limits_{x\in S}\{x\} xSx=xSmin{x} 知, S S S 中元素的值只能为 1 1 1;有根据最后一条说明 S S S 只能为 { 1 , 1 } \{1,1\} {1,1},当且仅当 k = 2 k=2 k=2 时存在这种方案。
  3. Mex ⁡ ( S ) = 1 \operatorname{Mex}(S)=1 Mex(S)=1 时,由最后一条知, ∑ x ∈ S x − max ⁡ x ∈ S x = 1 \sum\limits_{x\in S} x-\max\limits_{x\in S}{x}=1 xSxxSmaxx=1,显然除最大值外其他值的和要不为 0 0 0,要不大于 1 1 1,故无解。
  4. Mex ⁡ ( S ) = 2 \operatorname{Mex}(S)=2 Mex(S)=2 时, 0 , 1 ∈ S 0,1\in S 0,1S,若 1 1 1 S S S 中的最大值,则 S S S { 0 , 1 , 1 , 1 } \{0,1,1,1\} {0,1,1,1};否则, S S S { 0 , 1 , 1 , x } , x > 2 \{0,1,1,x\},x>2 {0,1,1,x},x>2
  5. Mex ⁡ ( S ) = 3 \operatorname{Mex}(S)=3 Mex(S)=3 时, 0 , 1 , 2 ∈ S 0,1,2\in S 0,1,2S,若 2 2 2 S S S 中的最大值,则 S = { 0 , 1 , 1 , 1 , 2 } 或 { 0 , 1 , 2 , 2 } S=\{0,1,1,1,2\}或\{0,1,2,2\} S={0,1,1,1,2}{0,1,2,2};否则, S = { 0 , 1 , 1 , 1 , x } , x > 3 S=\{0,1,1,1,x\},x>3 S={0,1,1,1,x},x>3
  6. Mex ⁡ ( S ) = 4 \operatorname{Mex}(S)=4 Mex(S)=4 时, 0 , 1 , 2 , 3 ∈ S 0,1,2,3\in S 0,1,2,3S,则 3 3 3 一定为 S S S 的最大值,故 S = { 0 , 1 , 1 , 2 , 3 } S=\{0,1,1,2,3\} S={0,1,1,2,3}
  7. Mex ⁡ ( S ) > 4 \operatorname{Mex}(S)>4 Mex(S)>4 时,由于 ( n − 2 ) ( n − 1 ) 2 > Mex ⁡ ( S ) = n \frac{(n-2)(n-1)}{2}>\operatorname{Mex}(S)=n 2(n2)(n1)>Mex(S)=n,故无解。
  8. 对于操作 4 4 4 5 5 5 6 6 6 中集合中的零元素,其可以是任意个。
  9. 时间复杂度为 O ( T ) \mathcal O(T) O(T)

代码

#include <bits/stdc++.h>
using namespace std;
long long n, k, t;
void read (long long &x) 
{
	x = 0; int w = 1;
	char ch = getchar ();
	while (ch < '0' || ch > '9') 
	{
		if (ch == '-') w = -1;
		ch = getchar ();
	}
	while (ch >= '0' && ch <= '9') 
	{
		x = (x << 1) + (x << 3) + ch - 48;
		ch = getchar (); 
	}
	x *= w;
} 
int main ()
{
	read (t);
	while (t--) 
	{
		long long ans = 0;
		read (n), read (k);
		if (k == 2 && n >= 1) ans ++;
		if (k >= 4 && n >= 1) ans ++;
		if (k >= 5 && n >= 2) ans ++;
		if (k >= 4 && n >= 2) ans ++;
		if (k >= 5 && n >= 3) ans ++;
		if (n > 2 && k >= 4) ans += (n - 2);
		if (n > 3 && k >= 4) ans += (n - 3);
		printf ("%lld\n", ans);
	}
	return 0;
}

收获

  1. 找准分类讨论的依据很重要。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值