洛谷P1154 奶牛分厩(数论)

【题目描述】
农夫约翰有 N ( 1 ≤ N ≤ 5000 ) N(1 \leq N \leq 5000) N(1≤N≤5000)头奶牛,每头奶牛都有一个唯一的不同于其它奶牛的编号 s i s_i si​ ,所有的奶牛都睡在一个有 K K K个厩的谷仓中,厩的编号为 0 0 0到 K − 1 K−1 K−1。每头奶牛都知道自己该睡在哪一个厩中,因为约翰教会了它们做除法, S i   m o d   K S_i \bmod K Si​modK的值就是第 i i i头奶牛所睡的厩的编号。
给出一组奶牛的编号,确定最小的 K K K使得没有两头或两头以上的奶牛睡在同一厩中。

【输入格式】
第一行一个正整数 N N N,第 2 2 2到 N + 1 N+1 N+1行每行一个整数表示一头奶牛的编号。

【输出格式】
一个整数,表示要求的最小的 K K K,对所有的测试数据这样的 K K K是一定存在的。

【数据范围】
1 ≤ S i ≤ 1000000 1\leq S_i\leq 1000000 1≤Si​≤1000000

【输入样例】

5
4
6
9
10
13

【输出样例】

8

【分析】
首先 a , b a,b a,b在 m o d   k mod\ k mod k意义下同余,当且仅当 k ∣ ( a − b ) k|(a-b) k∣(a−b)即 k k k是 ( a − b ) (a-b) (a−b)的一个因子。
这个证明可以考虑 m o d mod mod运算的意义。也可以 a % k = b % k a\% k=b\% k a%k=b%k等价于 a − b = 0 ( m o d   k ) a-b=0(mod\ k) a−b=0(mod k)。
因为 s ≤ 1 0 6 s\leq 10^6 s≤106所以可以预处理出所有差值,并把他们打上标记。
接着从 n n n开始从小到大枚举,如果一个数 x x x未被标记,那么我们就看他的所有倍数(不超过 K K K)是否被标记。如果都没被标记,则说明 x x x是合法的,输出 x x x即可。

【代码】

#include <iostream>
#include <cmath>
using namespace std;

const int N = 5010, K = 1000010;
int a[N];
bool st[K];//标记a-b
int n;

int main()
{
	cin >> n;
	for (int i = 0; i < n; i++) cin >> a[i];
	//预处理所有数之间的差值a-b
	for (int i = 0; i < n - 1; i++)
		for (int j = i + 1; j < n; j++)
			st[abs(a[i] - a[j])] = true;
	//从小到大枚举k
	for (int i = n; i < K; i++)
		if (!st[i])
		{
			bool flag = true;
			for (int j = i + i; j < K; j += i)//判断i是否是a-b的因子
				if (st[j])
				{
					flag = false;
					break;
				}
			if (flag)
			{
				cout << i << endl;
				break;
			}
		}
	return 0;
}
上一篇:P3639-[APIO2013]道路费用【最小生成树】


下一篇:如何快速计算组合数