首页 > 其他分享 >【UER #11】科考工作

【UER #11】科考工作

时间:2023-06-20 10:35:26浏览次数:44  
标签:11 int 质数 个数 cdots 科考 倍数 UER define

link

  • 给定 \(2n-1\) 个 \([0,n-1]\) 中的整数,选择恰好 \(n\) 个使得和为 \(n\) 的倍数。保证 \(n\) 为质数。
  • \(n\leq 3\times 10^5\)。

本质思想就是若在 \(\bmod n\) 意义下,对于任意 \(x\in[0,n-1]\) 集合 \(s\) 满足 \(s\cup s+x = s\)(即对于任意集合中的数 \(y\),\((y+x)\bmod n\in s\)),那么 \(s\) 必定 \(=\{0,1,\cdots, n-1\}\)。

这个结论还是比较显然的,考虑 \(0,x,2x,3x, \cdots, (n-1)x\) 在 \(\bmod n\) 意义下构成了长度为 \(n\) 的环,因为一定有 \(0\in s\),故如果有数不在 \(s\) 中,那么一定能找到相邻的两个数 \(kx, (k+1)x\),使得 \(kx\in s, (k+1)x\not \in s\),得到矛盾。

回到原问题,先任意选出一个数扔一边,再给剩下的 \(2n-2\) 个数两两配对,使得配对的两数不同。如果无法达到说明有一种数字出现次数 \(>n-1\),直接输出 \(n\) 个这种数即可。

之后先选择每个配对中的第一个数,结合一开始扔出去的数得到和为 \(s\) 的 \(n\) 个数。对于每个配对 \((a,b)\) 处理出反悔的贡献 \(d = b-a\),现在变成要求选出集合 \(d\) 的一个子集使得和为 \(-s\)。

要做的就是循环 01 背包,根据一开始的结论每次至少在集合中新增一个数,所以一定有解。

至少可以用 bitset 优化到 \(O(\frac{n^2}{\omega})\),利用 二分 + Hash 每次在循环背包上精准定位 \(0\to 1\) 的位置可以做到 \(O(n\log ^2 n)\)(动态 Hash 需要树状数组),同时还有两倍常数(会有同样多个 \(1\to 0\) 被定位到)。

更进一步的,这里每次让集合新增恰好一个数就足够了,并且已知 \(0\in s\),只需要找到任意一个不在集合中的数 \(c\),解出 \(c = kd\),那么序列在 \(0,d,2d,\cdots, kd\) 这个首为 \(1\) 尾为 \(0\) 的部分中一定有相邻的 \((1, 0)\),这是经典的可二分的结构。

code
#include<bits/stdc++.h>
typedef long long ll;
typedef unsigned long long ull;
#define rep(i, a, b) for(int i = (a); i <= (b); i ++)
#define per(i, a, b) for(int i = (a); i >= (b); i --)
#define Ede(i, u) for(int i = head[u]; i; i = e[i].nxt)
using namespace std;

#define eb emplace_back
typedef pair<int, int> pii;
#define mp make_pair
#define fi first
#define se second

inline int read() {
	int x = 0, f = 1; char c = getchar();
	while(c < '0' || c > '9') f = (c == '-') ? - 1 : 1, c = getchar();
	while(c >= '0' && c <= '9') x = x * 10 + c - 48, c = getchar();
	return x * f;
}

const int N = 3e5 + 10;
int n, a[N << 1], d[N]; pii b[N];
int f[N]; bool r[N];

int p[N << 1];
void solve1() {
	rep(i, 1, (n << 1) - 2) p[i] = i;
	sort(p + 1, p + (n << 1) - 1, [](int x, int y) {return a[x] < a[y];});
	
	rep(i, 1, n - 1) {
		if(a[p[i]] == a[p[i + n - 1]]) {
			rep(j, 1, n) printf("%d%c", p[i + j - 1], j == n ? '\n' : ' ');
			exit(0);
		}
		b[i] = mp(p[i], p[i + n - 1]);
		d[i] = (a[p[i + n - 1]] - a[p[i]] + n) % n;
	}
}

void exgcd(int a, int b, int &x, int &y) {
	if(!b) return x = 1, y = 0, void();
	exgcd(b, a % b, x, y);
	int z = x; x = y, y = z - y * (a / b);
}

int calc(int b, int a) {
	int x, y; exgcd(a, n, x, y);
	x = (x % n + n) % n;
	return 1ll * x * b % n;
}

void solve2() {
	
	f[0] = -1; int c = 1;
	rep(i, 1, n - 1) {
		int l = 1;
		int r = calc(c, d[i]);
		
		while(l < r) {
			int mid = (l + r) >> 1;
			int cur = 1ll * mid * d[i] % n;
			if(!f[cur]) r = mid; else l = mid + 1;
		}
		
		f[1ll * l * d[i] % n] = i;
		while(c < n && f[c]) c ++;
		if(c == n) break;
	}
	
	int s = a[(n << 1) - 1];
	rep(i, 1, n - 1) s = (s + a[b[i].fi]) % n;
	s = (n - s) % n;
	
	while(s) {
		r[f[s]] = true;
		s = (s - d[f[s]] + n) % n;
	}
}

int main() {
	n = read();
	rep(i, 1, (n << 1) - 1) a[i] = read();
	
	solve1();
	solve2();
	
	rep(i, 1, n - 1) printf("%d ", r[i] ? b[i].se : b[i].fi);
	printf("%d\n", (n << 1) - 1);
	return 0;
}

实际上,这题是可以扩展到 \(n\) 为非质数的!主要问题是此时 \(0,x,2x,\cdots\) 的环大小可能 \(<n\),所以上述做法不成立,但是既然有了质数的解法,不妨尝试分解质因数。

假设 \(n=mp\),其中 \(p\) 为质数。现在序列中有 \(2mp -1= (2m-1)p+(p-1)\) 个数。考虑先任意扔出 \(p-1\) 个数,再将剩下的每 \(p\) 个分为一组,构成 \(2m-1\) 组,且每一组的和均为 \(p\) 的倍数。这个是可以做到的,因为每次可以直接选出 \(p\) 个数,和扔出的 \(p-1\) 个数组成 \(2p-1\) 个数,从中选 \(p\) 个构成 \(p\) 的倍数就是之前的问题,处理后将不用的 \(p-1\) 个数继续扔出来即可。

之后就会有 \(2m-1\) 组数,以及 \(p-1\) 个数。直接不要那 \(p-1\) 个数,而是在组中选,因为每组的和都是 \(p\) 的倍数,所以可以直接将 每组的和除以 \(p\) 作为一个新的序列,递归到在 \(2m-1\) 个数中选择 \(m\) 的倍数的子问题。

因为不断递归必然回到质数问题,而质数一定有解,所以这样一定有解!

于是我们就成功构造性的证明了:给定任意 \(2n-1\) 个 \([0,n-1]\) 中的整数,都能够选择恰好 \(n\) 个使得和为 \(n\) 的倍数。这个事实。

标签:11,int,质数,个数,cdots,科考,倍数,UER,define
From: https://www.cnblogs.com/lpf-666/p/17492935.html

相关文章

  • 从零开始学Python第11课:常用数据结构之字符串
    第二次世界大战促使了现代电子计算机的诞生,世界上的第一台通用电子计算机名叫ENIAC(电子数值积分计算机),诞生于美国的宾夕法尼亚大学,占地167平米,重量约27吨,每秒钟大约能够完成约5000次浮点运算,如下图所示。ENIAC诞生之后被应用于导弹弹道的计算,而数值计算也是现代电子计算机最为重......
  • PAT (Advanced Level)_1100 Mars Numbers (20分)(C++_模拟)
    PeopleonMarscounttheirnumberswithbase13:ZeroonEarthiscalled"tret"onMars.Thenumbers1to12onEarthiscalled"jan,feb,mar,apr,may,jun,jly,aug,sep,oct,nov,dec"onMars,respectively.Forthenexthigherdigi......
  • 【雕爷学编程】Arduino动手做(117)---P10V706LED屏模组
    37款传感器与执行器的提法,在网络上广泛流传,其实Arduino能够兼容的传感器模块肯定是不止这37种的。鉴于本人手头积累了一些传感器和执行器模块,依照实践出真知(一定要动手做)的理念,以学习和交流为目的,这里准备逐一动手尝试系列实验,不管成功(程序走通)与否,都会记录下来—小小的进步或是搞......
  • BUUCTF:[CISCN2019 华东南赛区]Web11
    注意到了banner中信息说是smarty,并且将XFF输出到页面直接尝试Smarty模板注入{$smarty.version}Smarty3官方手册:https://www.smarty.net/docs/zh_CN/language.function.if.tpl{ifsystem('ls-lha/')}{/if}{ifsystem('cat/flag')}{/if}......
  • 'utf-8' codec can't decode byte 0xbc in position 1182: invalid start byte
    2.如果是字符集出现错误,建议多选择几种字符集测试一下:选择的经验是:如果是爬取到的网页文件,可以查看网页文件的meta标签下的charset属性值。例如:<metacharset="UTF-8">1也可以使用notepad++打开,查看下右下角的部位,会指示该文件是那种编码。 用一个例子来演示会更加清晰......
  • C++11:多线程
    传统的C++(C++11之前)中并没有引入线程这个概念C++11引入了头文件<thread>,提供了管理线程保护共享数据线程间同步操作原子操作等  <thread>join()detach()get_id()yield()sleep_for()sleep_until() #include<thread>intmain(){ std::threadt......
  • 云原生周刊:Dapr v1.11 发布
    开源项目推荐KamajiKamaji可以大规模地部署和运行Kubernetes控制平面,而只需承担一小部分操作负担。Kamaji的特别之处在于,控制平面组件是在一个单一的pod中运行,而不是在专用机器中运行。这种解决方案使运行多个控制平面的成本更低,更容易部署和操作。RobustaKRRRobustaK......
  • C++11:Lambda表达式
    Lambda表达式为了一些简单的函数直接调用封装[var]:表示值传递方式捕捉变量var[=]:表示值传递捕捉所有父作用域中的变量(包括成员函数中的this)[&var]:表示引用传递捕捉变量var[&]:表示引用传递捕捉所有父作用域中的变量(包括成员函数中的this)[this]:表示值传递方式捕捉当前的this指......
  • The remote SSH server rejected X11 forwarding request.“远程SSH服务器拒绝X11转发
       启动kkFileView后弹出提醒无法正常访问服务器, 重启服务器时,需要安装出现如下提醒方法一、 X11forwarding依赖xorg-x11-xauth软件包,需要先安装xorg-x11-xauth软件包。1.使用Xshell执行下面代码[root@VM-4-11-centos~]#yuminstallxorg-x11-xauth  ......
  • 数据结构课程设计2023夏7-11 二路归并排序
    给定一个整数序列,请按非递减序输出采用二路归并排序(递归法)的各趟排序后的结果(每完成一次归并操作就输出归并后的结果)。输入格式:测试数据有多组,处理到文件尾。每组测试数据第一行输入一个整数n(1≤n≤100),第二行输入n个整数。输出格式:对于每组测试,输出若干行,每行是一趟排序后的......