2021“MINIEYE杯”中国大学生算法设计超级联赛(9)——H - Integers Have Friends 2.0

该博客探讨了一道编程题目,涉及数组处理和数论概念。通过证明gcd(∣x−y∣,∣z−y∣)>1在模同余条件下的重要性,提出了一个算法策略,即随机选取数组中的两个数,计算它们差值的质因子,并寻找模数相同的元素个数,从而找到最长的子序列。最后,通过不断优化这个过程来求解问题的最大值。
摘要由CSDN通过智能技术生成

H-Integers_Have_Friends2.0

题意:

给出一个数组 a a a,找到一个最长的子序列 b b b,存在 m ( m > 1 ) m(m>1) m(m>1)使 b i   m o d   m = b j   m o d   m b_i~mod~m=b_j~mod~m bi mod m=bj mod m

思路:

我们先了解 x   m o d   m = y   m o d   m = z   m o d   m x~mod~m=y~mod~m=z~mod~m x mod m=y mod m=z mod m,则 g c d ( ∣ x − y ∣ , ∣ z − y ∣ ) > 1 gcd(|x-y|,|z-y|)>1 gcd(xy,zy)>1

证明:

假设 g c d ( ∣ x − y ∣ , ∣ z − y ∣ ) = 1 gcd(|x-y|,|z-y|)=1 gcd(xy,zy)=1 存在 m ( m > 1 ) m(m>1) m(m>1)使得 x   m o d   m = y   m o d   m = z   m o d   m x~mod~m=y~mod~m=z~mod~m x mod m=y mod m=z mod m

则: x = k 1 m + u , y = k 2 m + u , z = k 3 m + u x=k_1m+u,y=k_2m+u,z=k_3m+u x=k1m+u,y=k2m+u,z=k3m+u,所以 ∣ x − y ∣ = ∣ ( k 1 − k 2 ) m ∣ , ∣ z − y ∣ = ∣ ( k 3 − k 2 ) m ∣ |x-y|=|(k_1-k2)m|,|z-y|=|(k_3-k_2)m| xy=(k1k2)mzy=(k3k2)m,因为 m > 1 m>1 m>1,所以 g c d ( ∣ x − y ∣ , ∣ z − y ∣ ) > = m > 1 gcd(|x-y|,|z-y|)>=m>1 gcd(xy,zy)>=m>1

所以假设不成立,得证 x   m o d   m = y   m o d   m = z   m o d   m x~mod~m=y~mod~m=z~mod~m x mod m=y mod m=z mod m,则 g c d ( ∣ x − y ∣ , ∣ z − y ∣ ) > 1 gcd(|x-y|,|z-y|)>1 gcd(xy,zy)>1

现在我们从a数组中随机出两个数字,它们两个同时在最长子序列的概率很大,所以我们就随机选出两个数字,验证它们差值的全部质因子,返回在a数组中模数相同的个数。再取一个最大值。

#include <bits/stdc++.h>

using namespace std;
const int N = 2e6+10;
const int inf = 1e9+10;
typedef long long ll;
// #define int long long
const int K=30;
mt19937_64 gen(time(0));
ll a[N];
int p[N], tot;
bitset<N> st;
void init() {
    for(int i=2; i<N; i++) {
        if(!st[i]) p[tot++] = i;
        for(int j=0; j<tot&&1ll*i*p[j]<N; j++) {
            st[i*p[j]] = 1;
            if(i % p[j] == 0) break;
        }
    }
}
int n;
int C(ll pp, ll y) {
    int cnt = 0;
    for(int i=1; i<=n; i++) {
        if(a[i] % pp == y) cnt++; 
    }
    return cnt;
}
int main() {
#ifndef ONLINE_JUDGE
    freopen("in.txt", "r", stdin);
    freopen("out.txt", "w", stdout);
#endif
    init();
    int t;
    scanf("%d", &t);
    while(t--) { 
        int k = 30, ans = 1;
        
        scanf("%d", &n);
        for(int i=1; i<=n; i++) scanf("%lld", &a[i]);
        while(k--) {
            int x, y;
            while(1) {
                x = gen() % n + 1;
                y = gen() % n + 1;
                if(x != y) break;
            }
            ll tmp = abs(a[x] - a[y]);
            for(int i=0; 1ll*p[i]*p[i]<=tmp; i++) {
                if(tmp % p[i] == 0) {
                    ans = max(ans, C(p[i], a[x]%p[i]));
                    while(tmp % p[i] == 0) tmp /= p[i];
                }
            }
            if(tmp > 1) ans = max(ans, C(tmp, a[x]%tmp));
        }
        printf("%d\n", ans);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值