打了网络赛,还可以,但是不知道哪里可以补题,就写写思路吧
这道题关键就是从特例推出普遍规律,先讨论简单的情况
稍微分析一下可以发现,只有2的次幂影响结果,所以设两数为pt 2pt
t为奇数,p为2的次幂,t不影响结果所以设t=1
如果是1 2 显然2的人赢
如果是4 2 2的人说自己i dont know那么到4的时候就知道自己不是1,4的人赢
如果是4 8 4的人说自己i dont know 8的人就知道自己不是2,8的人赢
总结一下,数字大的人赢,这里有点递推的感觉。
这题不难,不要有畏难情绪,自己给自己设限
稍微推一下,设l为l/x上取整,r为r/x上取整,那么K=2^(r-l-1)x(l+r)(r-l+1)
这个式子的变量是x,l和r是题目给的。可以发现x是K的因子,对于这个式子,只要确定了x,那么可以计算l和r,那么就可以验证是否等于K
因子需要求K的所有因子,K是10^14,直接根号K枚举的话加上多组数据会T。因此考虑对K进行质因数分解,通过枚举指数来枚举因子。
这里有两种方法,一种是预处理10^7的质数,用这些质数去质因数分解,一种是大数分解。
主要是熟悉板子
Miller_Rabin素数测试可以迅速测试一个大数(long long级别)是否为质数
pollard_rho算法可以对一个long long级别的数质因数分解。
注意板子中质因数分解的结果是无序重复的素数,如24就是2 3 2 2
#include
#include
#include
#include
#define rep(i, a, b) for(int i = (a); i < (b); i++)
#define _for(i, a, b) for(int i = (a); i <= (b); i++)
using namespace std;
typedef long long ll;
const int S = 8;
ll mult_mod(ll a, ll b, ll c)
{
a %= c;
b %= c;
ll ret = 0, tmp = a;
while(b)
{
if(b & 1)
{
ret += tmp;
if(ret > c) ret -= c;
}
tmp <<= 1;
if(tmp > c) tmp -= c;
b >>= 1;
}
return ret;
}
ll pow_mod(ll a, ll n, ll mod)
{
ll ret = 1;
ll temp = a % mod;
while(n)
{
if(n & 1) ret = mult_mod(ret, temp, mod);
temp = mult_mod(temp, temp, mod);
n >>= 1;
}
return ret;
}
bool check(ll a, ll n, ll x, ll t)
{
ll ret = pow_mod(a, x, n);
ll last = ret;
_for(i, 1, t)
{
ret = mult_mod(ret, ret, n);
if(ret == 1 && last != 1 && last != n - 1) return true;
last = ret;
}
if(ret != 1) return true;
return false;
}
bool Miller_Rabin(ll n)
{
if(n < 2) return false;
if(n == 2) return true;
if((n & 1) == 0) return false;
ll x = n - 1, t = 0;
while((x & 1) == 0) x >>= 1, t++;
srand(time(0));
rep(i, 0, S)
{
ll a = rand() % (n - 1) + 1;
if(check(a, n, x, t)) return false;
}
return true;
}
ll factor[100]; //储存质因数分解结果 有重复 无序
int tol; //标号0~tol-1
ll gcd(ll a, ll b)
{
ll t;
while(b)
{
t = a;
a = b;
b = t % b;
}
if(a >= 0) return a;
return -a;
}
ll pollard_rho(ll x, ll c)
{
ll i = 1, k = 2;
srand(time(0));
ll x0 = rand() % (x - 1) + 1;
ll y = x0;
while(1)
{
i++;
x0 = (mult_mod(x0, x0, x) + c) % x;
ll d = gcd(y - x0, x);
if(d != 1 && d != x) return d;
if(y == x0) return x;
if(i == k) y = x0, k += k;
}
}
void findfac(ll n, ll k)
{
if(n == 1) return;
if(Miller_Rabin(n))
{
factor[tol++] = n;
return;
}
ll p = n;
int c = k;
while(p >= n) p = pollard_rho(p, c--);
findfac(p, k);
findfac(n / p, k);
}
int main()
{
int T; scanf("%d", &T);
while(T--)
{
ll n;
scanf("%lld", &n);
if(Miller_Rabin(n)) puts("Prime");
else
{
tol = 0;
findfac(n, 107);
ll ans = factor[0];
rep(i, 1, tol)
ans = min(ans, factor[i]);
printf("%lld\n", ans);
}
}
return 0;
}
二分答案读完题就知道了,关键是确定了最大值后,怎么操作使得删掉的边最少,这是这道题的关键。
这里要用到树形dp,dp[u]表示以u为根的子树符合条件的情况下,u所在的连通块的权值和是多少。
那么每次u自己和全部dp[v]算上,如果超过了最大值,那么就考虑删边。
为了使得删的边数最少,一次删边要去掉尽可能多的权值,所以删去最大的dp[v],还是超就删第二大的dp[v]以此类推。
这样子贪心下来就可以求出删了多少边了
#include
#define rep(i, a, b) for(int i = (a); i < (b); i++)
#define _for(i, a, b) for(int i = (a); i <= (b); i++)
using namespace std;
typedef long long ll;
const int N = 2e5 + 10;
int a[N], n, k, mx, cnt;
vector g[N];
ll key, dp[N];
void dfs(int u, int fa)
{
dp[u] = a[u];
ll sum = a[u];
vector ve;
for(int v: g[u])
{
if(v == fa) continue;
dfs(v, u);
ve.push_back(dp[v]);
sum += dp[v];
}
if(!ve.size()) return;
sort(ve.begin(), ve.end(), greater());
rep(i, 0, ve.size())
{
if(sum > key) sum -= ve[i], cnt++;
else break;
}
dp[u] = sum;
}
bool check(ll x)
{
cnt = 0;
key = x;
dfs(1, 0);
return cnt <= k;
}
int main()
{
int T, kase = 0;
scanf("%d", &T);
while(T--)
{
mx = 0;
scanf("%d%d", &n, &k); k--;
_for(i, 1, n) g[i].clear();
_for(i, 1, n - 1)
{
int u, v;
scanf("%d%d", &u, &v);
g[u].push_back(v);
g[v].push_back(u);
}
_for(i, 1, n) scanf("%d", &a[i]), mx = max(mx, a[i]);
ll l = mx - 1, r = 1e15;
while(l + 1 < r)
{
ll m = l + r >> 1;
if(check(m)) r = m;
else l = m;
}
printf("Case #%d: %lld\n", ++kase, r);
}
return 0;
}
很容易发现操作几次就变1了,考虑怎么让它最小。
注意到每次操作都是变小的,所以如果一个数是最大的,大于另一个序列的最大值,那么它一定要变小,这个是必须要操作的。因此就根据这一点,比较两者的最大值,相等就不用操作,否则就变小,用优先队列实现。
cf题解的stl用的很秀啊,代码很短。
#include
#define rep(i, a, b) for(int i = (a); i < (b); i++)
#define _for(i, a, b) for(int i = (a); i <= (b); i++)
using namespace std;
int main()
{
int T; scanf("%d", &T);
while(T--)
{
int n; scanf("%d", &n);
vector a(n), b(n);
rep(i, 0, n) scanf("%d", &a[i]);
rep(i, 0, n) scanf("%d", &b[i]);
int ans = 0;
priority_queue qa(a.begin(), a.end());
priority_queue qb(b.begin(), b.end());
while(!qa.empty())
{
if(qa.top() == qb.top())
{
qa.pop(); qb.pop();
continue;
}
else if(qa.top() > qb.top())
{
qa.push(to_string(qa.top()).size());
qa.pop(); ans++;
}
else
{
qb.push(to_string(qb.top()).size());
qb.pop(); ans++;
}
}
printf("%d\n", ans);
}
return 0;
}
但我比赛时是另一个思路,大致是先去重,然后把二位数以上的操作,再去重,然后把非1的操作。但是我写去重的时候用了很多stl,常数很大,赛时AC,赛后T了……
其实就排个序然后用两个指针即可,不用弄那么复杂。改成这么写后AC了
#include
#define rep(i, a, b) for(int i = (a); i < (b); i++)
#define _for(i, a, b) for(int i = (a); i <= (b); i++)
using namespace std;
const int N = 2e5 + 10;
int a[N], b[N], visa[N], visb[N], n;
vector va, vb;
int get(int x)
{
int res = 0;
while(x)
{
x /= 10;
res++;
}
return res;
}
void deal(int a[], int b[], int n)
{
_for(i, 1, n) visa[i] = visb[i] = 0;
sort(a + 1, a + n + 1);
sort(b + 1, b + n + 1);
int pa = 1, pb = 1;
while(pa <= n && pb <= n)
{
if(a[pa] == b[pb])
{
visa[pa] = visb[pb] = 1;
pa++; pb++;
}
else if(a[pa] > b[pb]) pb++;
else pa++;
}
va.clear();
vb.clear();
_for(i, 1, n)
if(!visa[i])
va.push_back(a[i]);
_for(i, 1, n)
if(!visb[i])
vb.push_back(b[i]);
}
int main()
{
int T; scanf("%d", &T);
while(T--)
{
scanf("%d", &n);
_for(i, 1, n) scanf("%d", &a[i]);
_for(i, 1, n) scanf("%d", &b[i]);
deal(a, b, n);
int ans = 0;
rep(i, 0, va.size())
if(va[i] >= 10)
{
va[i] = get(va[i]);
ans++;
}
rep(i, 0, vb.size())
if(vb[i] >= 10)
{
vb[i] = get(vb[i]);
ans++;
}
int cnt = 0;
for(int x: va) a[++cnt] = x;
cnt = 0;
for(int x: vb) b[++cnt] = x;
deal(a, b, cnt);
rep(i, 0, va.size())
if(va[i] > 1)
ans++;
rep(i, 0, vb.size())
if(vb[i] > 1)
ans++;
printf("%d\n", ans);
}
return 0;
}
之前做过一道优点类似的,也是赢平局输,用dp做的,这题也类似。
考试时用dp过的,但是写的比较复杂,但大体思路和题解是一致的
我是在状态转移分类讨论的,而题解是直接取min max的,写起来很方便
令1为Alice,0为Draw,-1为Bob
那么Alice的目标是使值变大,Bob是使值变小,所以就转化成了博弈里面的min-max搜索。
#include
#define rep(i, a, b) for(int i = (a); i < (b); i++)
#define _for(i, a, b) for(int i = (a); i <= (b); i++)
using namespace std;
const int N = 2000 + 10;
int dp[N][N], n;
char s[N];
int check(char a, char b)
{
return a > b ? 1 : (a == b ? 0 : -1);
}
int main()
{
int T; scanf("%d", &T);
while(T--)
{
scanf("%s", s + 1);
n = strlen(s + 1);
_for(i, 1, n - 1)
{
if(s[i] == s[i + 1]) dp[i][i + 1] = 0;
else dp[i][i + 1] = 1;
}
for(int len = 4; len <= n; len += 2)
_for(l, 1, n)
{
int r = l + len - 1;
if(r > n) break;
int cl = 1;
if(dp[l + 1][r - 1] != 0) cl = min(cl, dp[l + 1][r - 1]);
else cl = min(cl, check(s[l], s[r]));
if(dp[l + 2][r] != 0) cl = min(cl, dp[l + 2][r]);
else cl = min(cl, check(s[l], s[l + 1]));
int cr = 1;
if(dp[l + 1][r - 1] != 0) cl = min(cl, dp[l + 1][r - 1]);
else cr = min(cr, check(s[r], s[l]));
if(dp[l][r - 2] != 0) cl = min(cl, dp[l][r - 2]);
else cr = min(cr, check(s[r], s[r - 1]));
dp[l][r] = max(cl, cr);
}
if(dp[1][n] == 1) puts("Alice");
else if(dp[1][n] == -1) puts("Bob");
else puts("Draw");
}
return 0;
}
还有一种O(n)的做法,比赛时我就猜测Bob不可能赢,我尝试构造了Bob赢得情况没构造出来。
如果有了这个结论,那么其实只要判断什么时候平局即可,不是平局就是Alice赢
如果是平局,那么就是两边拿到字符串是一样的,考虑什么时候会一样。
因为每次拿都是两侧的,或者一侧两个,那么需要它们是一样的。
两侧一样的就是对称的,一侧两个就是aabbcc这样
那么都存在呢,可以发现可以外面是对称的,里面是aabbcc的,那么判断是否是这样的串就可以了
#include
#define rep(i, a, b) for(int i = (a); i < (b); i++)
#define _for(i, a, b) for(int i = (a); i <= (b); i++)
using namespace std;
const int N = 2000 + 10;
char s[N];
int n;
int main()
{
int T; scanf("%d", &T);
while(T--)
{
scanf("%s", s + 1);
n = strlen(s + 1);
int l = 1, r = n;
while(l < r && s[l] == s[r]) l++, r--;
int flag = 1;
for(int i = l; i <= r; i += 2)
if(s[i] != s[i + 1])
{
flag = 0;
break;
}
puts(flag ? "Draw" : "Alice");
}
return 0;
}
这种切割的,就设在以u为根的子树中,包含u的联通块即可
还要分当前联通块是否有一个黑色,然后分类讨论即可。
注意儿子所在联通块无黑色时不能切断
#include
#define rep(i, a, b) for(int i = (a); i < (b); i++)
#define _for(i, a, b) for(int i = (a); i <= (b); i++)
using namespace std;
typedef long long ll;
const int N = 1e5 + 10;
const int mod = 1e9 + 7;
vector g[N];
ll dp[N][2];
int c[N], n;
ll binpow(ll a, ll b)
{
ll res = 1;
for(; b; b >>= 1)
{
if(b & 1) res = res * a % mod;
a = a * a % mod;
}
return res;
}
ll inv(ll x) { return binpow(x, mod - 2); }
void dfs(int u, int fa)
{
ll res = 1;
if(c[u] == 1)
{
for(int v: g[u])
{
if(v == fa) continue;
dfs(v, u);
if(c[v]) res = res * dp[v][1] % mod;
else res = res * (dp[v][1] + dp[v][0]) % mod;
}
dp[u][1] = res;
}
else
{
for(int v: g[u])
{
if(v == fa) continue;
dfs(v, u);
if(c[v]) res = res * dp[v][1] % mod;
else res = res * (dp[v][1] + dp[v][0]) % mod;
}
dp[u][0] = res;
ll sum = 0;
for(int v: g[u])
{
if(v == fa) continue;
if(c[v]) sum = (sum + res) % mod;
else sum = (sum + res * inv(dp[v][1] + dp[v][0]) % mod * dp[v][1] % mod) % mod;
}
dp[u][1] = sum;
}
}
int main()
{
scanf("%d", &n);
_for(i, 2, n)
{
int x; scanf("%d", &x); x++;
g[x].push_back(i);
g[i].push_back(x);
}
_for(i, 1, n) scanf("%d", &c[i]);
dfs(1, 0);
printf("%lld\n", dp[1][1]);
return 0;
}
从提问的方式可以看出是二分答案
二分一个答案,然后先删点。删点的实现可以用一个数组标记,后面遍历点的时候都要判断这是没有被删去的点。注意新图的点数要重新计算,不是n
得到一个新图后,这时候点权没有用了,只需要判断是否存在长度大于等于k的路径
如果有环则一定存在,否则用拓扑排序加dp求最长度。判环用拓扑排序。
注意有-1的情况,二分的边界要注意一下
#include
#define rep(i, a, b) for(int i = (a); i < (b); i++)
#define _for(i, a, b) for(int i = (a); i <= (b); i++)
using namespace std;
typedef long long ll;
const int N = 2e5 + 10;
vector g[N];
int a[N], d[N], dp[N], ban[N], n, m;
ll k;
bool check(int key)
{
int cnt = 0;
_for(i, 1, n)
{
if(a[i] <= key) ban[i] = 0, cnt++, dp[i] = 1;
else ban[i] = 1;
d[i] = 0;
}
_for(u, 1, n)
for(int v: g[u])
if(!ban[u] && !ban[v])
d[v]++;
queue q;
vector topo;
_for(i, 1, n)
if(!ban[i] && !d[i])
q.push(i);
while(!q.empty())
{
int u = q.front(); q.pop();
topo.push_back(u);
for(int v: g[u])
if(!ban[v] && --d[v] == 0)
q.push(v);
}
if(topo.size() < cnt) return true;
int res = 0;
for(int u: topo)
for(int v: g[u])
if(!ban[v])
dp[v] = max(dp[v], dp[u] + 1);
for(int u: topo) res = max(res, dp[u]);
return res >= k;
}
int main()
{
scanf("%d%d%lld", &n, &m, &k);
_for(i, 1, n) scanf("%d", &a[i]);
while(m--)
{
int u, v;
scanf("%d%d", &u, &v);
g[u].push_back(v);
}
int l = 0, r = 1e9 + 1;
while(l + 1 < r)
{
int m = l + r >> 1;
if(check(m)) r = m;
else l = m;
}
printf("%d\n", r == 1e9 + 1 ? -1 : r);
return 0;
}
先考虑简单的情况,c全是0
可以发现确定了一个数,就有一堆数连着被确定,形成一个环。
于是ai和bi连边,就会形成很多个环。
环中的一个点确定了就都确定了,可以确定使用a或b
因此每一个大于1的环就有两种选择
对于c已经有数,就是已经确定了,不对答案有贡献。
#include
#define rep(i, a, b) for(int i = (a); i < (b); i++)
#define _for(i, a, b) for(int i = (a); i <= (b); i++)
using namespace std;
typedef long long ll;
const int mod = 1e9 + 7;
const int N = 1e5 + 10;
int f[N], a[N], b[N], ban[N], siz[N], n;
ll binpow(ll a, ll b)
{
ll res = 1;
for(; b; b >>= 1)
{
if(b & 1) res = res * a % mod;
a = a * a % mod;
}
return res;
}
int find(int x) { return f[x] == x ? x : f[x] = find(f[x]); }
void Union(int x, int y)
{
int fx = find(x), fy = find(y);
if(fx == fy) return;
siz[fx] += siz[fy];
f[fy] = fx;
}
int main()
{
int T; scanf("%d", &T);
while(T--)
{
scanf("%d", &n);
_for(i, 1, n) f[i] = i, ban[i] = 0, siz[i] = 1;
_for(i, 1, n) scanf("%d", &a[i]);
_for(i, 1, n) scanf("%d", &b[i]);
_for(i, 1, n) Union(a[i], b[i]);
_for(i, 1, n)
{
int x; scanf("%d", &x);
ban[find(x)] = 1;
}
int cnt = 0;
_for(i, 1, n)
if(f[i] == i && !ban[i] && siz[i] > 1)
cnt++;
printf("%lld\n", binpow(2, cnt));
}
return 0;
}
这题的关键就是像上一题一样,ai向bi连边可以形成环。如果没有做过上一题,很难想到
有环之后考虑怎么分配数字。一个直觉的想法是一大一小分配,这样让差最大,如何证明呢?
当存在a1 > a2 > a3时,对答案的贡献是等价于a1 > a3的,也就是中间的a2并没有用。那么对于任意一种分配,删去这种没有用的点后,一定是一大一小交替。而且可以发现,一大一小交替的话,个数一定是偶数。
这时大的绝对值取正,小的绝对值取负,所以我们让大的尽可能大,小的尽可能小。
因此,如果环是偶数,那么就大的位置放尽可能大的,小的放尽可能小的。
对于环是奇数,有一个位置是没有用的,所以要填一个最差的,也就是中间的值,把极值留给其他地方。
最后注意开long long
#include
#define rep(i, a, b) for(int i = (a); i < (b); i++)
#define _for(i, a, b) for(int i = (a); i <= (b); i++)
using namespace std;
typedef long long ll;
const int N = 1e5 + 10;
int f[N], a[N], b[N], v[N], n, l, r, pos;
vector k[N], num;
int find(int x) { return f[x] == x ? x : f[x] = find(f[x]); }
void Union(int x, int y) { f[find(x)] = find(y); }
ll cal(int x)
{
if(x <= 1) return 0;
if(x % 2 == 1) x--;
rep(i, 0, x) v[i] = num[pos++];
ll res = 0;
rep(i, 0, x)
{
int j = (i + 1) % x;
res += abs(v[j] - v[i]);
}
return res;
}
int main()
{
int T; scanf("%d", &T);
while(T--)
{
scanf("%d", &n);
_for(i, 1, n) f[i] = i, k[i].clear();
_for(i, 1, n) scanf("%d", &a[i]);
_for(i, 1, n) scanf("%d", &b[i]);
_for(i, 1, n) Union(a[i], b[i]);
_for(i, 1, n) k[find(i)].push_back(i);
ll ans = 0;
l = 1, r = n;
num.clear(); pos = 0;
while(l <= r)
{
num.push_back(l); l++;
num.push_back(r); r--;
}
_for(i, 1, n) ans += cal(k[i].size());
printf("%lld\n", ans);
}
return 0;
}
首先注意一波推导,注意余数取k而不是取0,因为数字要是正数,同时两边乘以2去掉分数
可以得到2n = k(k + 1 + 2t)
我自己做的时候推到这里就不知道怎么分析了
首先注意k和k+1+2t,一个是偶数一个奇数
也就是说2n可以分解为一个偶数和一个奇数相乘。
因为奇数部分没有2的因子
所以就直接把2n一直除以2来分解
然后就成了一个奇数和偶数。但是注意奇数部分不能为1,因为k和k+1+2t不可能为1
分解完之后,哪一个是k呢,注意到k+1+2t更大,所以k就取奇数和偶数更小的那个即可
#include
#define rep(i, a, b) for(int i = (a); i < (b); i++)
#define _for(i, a, b) for(int i = (a); i <= (b); i++)
using namespace std;
typedef long long ll;
int main()
{
int T; scanf("%d", &T);
while(T--)
{
ll n;
scanf("%lld", &n);
n *= 2;
ll t = 1;
while(n % 2 == 0)
{
n /= 2;
t *= 2;
}
if(n == 1) puts("-1");
else printf("%lld\n", min(t, n));
}
return 0;
}
首先可以发现,新出现的数肯定是当前数子集的gcd
然后每个数都是不同的,所以当前序列没有的数很少,那么就去枚举这些输数,然后枚举它的倍数,然后将它的倍数取gcd,如果是它那么就答案加一。
#include
#define rep(i, a, b) for(int i = (a); i < (b); i++)
#define _for(i, a, b) for(int i = (a); i <= (b); i++)
using namespace std;
unordered_map vis;
int n, mx;
int gcd(int a, int b) { return !b ? a : gcd(b, a % b); }
int main()
{
scanf("%d", &n);
_for(i, 1, n)
{
int x; scanf("%d", &x);
vis[x] = 1;
mx = max(mx, x);
}
int ans = 0;
_for(i, 1, mx)
if(!vis[i])
{
int cur = 0;
for(int j = i; j <= mx; j += i)
if(vis[j])
cur = gcd(cur, j);
if(cur == i) ans++;
}
printf("%d\n", ans);
return 0;
}
一开始的想法是枚举当前数的因数,然后用这个因数看是多少个数的公因数
一次的复杂度是max(根号ai,因数个数 * n) 我一开始算成根号ai*n了,然后觉得会T
#include
#define rep(i, a, b) for(int i = (a); i < (b); i++)
#define _for(i, a, b) for(int i = (a); i <= (b); i++)
using namespace std;
const int N = 50;
int a[N], n;
unordered_map mp;
int main()
{
int T; scanf("%d", &T);
while(T--)
{
mp.clear();
scanf("%d", &n);
int flag = 0;
_for(i, 1, n)
{
scanf("%d", &a[i]);
if(++mp[a[i]] >= n / 2) flag = 1;
}
if(flag)
{
puts("-1");
continue;
}
int ans = 1;
_for(id, 1, n)
{
vector ve;
_for(j, 1, n)
if(a[j] - a[id] >= 0)
ve.push_back(a[j] - a[id]);
if(ve.size() < n / 2) continue;
rep(i, 0, ve.size())
{
for(int j = 1; j * j <= ve[i]; j++)
if(ve[i] % j == 0)
{
int cnt = 0;
rep(k, 0, ve.size())
if(ve[k] % j == 0)
cnt++;
if(cnt >= n / 2) ans = max(ans, j);
cnt = 0;
rep(k, 0, ve.size())
if(ve[k] % (ve[i] / j) == 0)
cnt++;
if(cnt >= n / 2) ans = max(ans, ve[i] / j);
}
}
}
printf("%d\n", ans);
}
return 0;
}
题解的方法优美一些,把所有因子扔到map里面统计一下有无超过一半,注意相同的情况。
#include
#define rep(i, a, b) for(int i = (a); i < (b); i++)
#define _for(i, a, b) for(int i = (a); i <= (b); i++)
using namespace std;
const int N = 50;
int a[N], n;
unordered_map mp, vis;
int main()
{
int T; scanf("%d", &T);
while(T--)
{
mp.clear();
scanf("%d", &n);
int flag = 0;
_for(i, 1, n)
{
scanf("%d", &a[i]);
if(++mp[a[i]] >= n / 2) flag = 1;
}
if(flag)
{
puts("-1");
continue;
}
int ans = 1;
_for(id, 1, n)
{
int same = 0;
vector ve;
_for(j, 1, n)
{
if(a[j] - a[id] == 0) same++;
else if(a[j] - a[id] > 0) ve.push_back(a[j] - a[id]);
}
vis.clear();
rep(i, 0, ve.size())
{
for(int j = 1; j * j <= ve[i]; j++)
if(ve[i] % j == 0)
{
vis[j]++;
if(j * j != ve[i]) vis[ve[i] / j]++;
}
}
for(auto x : vis)
if(x.second + same >= n / 2)
ans = max(ans, x.first);
}
printf("%d\n", ans);
}
return 0;
}