[USACO24JAN] Cowlendar S题解

[USACO24JAN] Cowlendar S

题面

原题链接

简介:给出 \(a_1....a_n\),对所有满足 s 的 \(L\) 求和

s 为:

  1. \(\forall i,4 \times L \leq a_i\)
  2. \(a_i \bmod L\) 不超过 \(3\) 种不同的值。

\(1 \leq a_i \leq 4 \cdot 10^9\)

题解

一种暴力的做法是枚举 \(L\) ,然后 \(O(n)\) 检查是否合法,在这题的数据范围下显然难以通过。考虑发掘性质降低枚举量。

余数最多有三种,这个必要条件很强,我们考虑从它入手。根据鸽巢原理,对于所有合法的 \(L\) ,前 \(4\)\(a\) 在模 \(L\) 的意义下必然有两个同余,否则与这个必要条件相悖。同时对于两个模 \(L\) 同余的 \(a_i,a_j\),有 \(L \mid a_j-a_i\) 。我们考虑暴力配对前四个 \(a\) 作差,就能获得所有合法的 \(L\) 的倍数,对这些倍数枚举因子即可,最后再 \(O(n)\) 检查保证条件充要。

\(10^9\) 级别的数的因子个数最大只有 \(1000\) 左右,所以这样枚举大大降低了我们对 \(L\) 的枚举量,做题时留心观察题目限制,抓中某些很强的限制,往往都能引导正解。

const int N=1e5+5;
const int inf=1e18;
int n,a[N],mn=inf,len;
set<int> s;
bool chk(int x){
    set<int> num;
    for(int i=1;i<=len;i++){
        num.insert(a[i]%x);
        if(num.size()>3) return false;
    }
    return true;
}
void xpigeon(){
    cin>>n;
    for(int i=1;i<=n;i++){
        cin>>a[i];
        mn=min(mn,a[i]);
    }
    sort(a+1,a+n+1);
    len=unique(a+1,a+n+1)-(a+1);
    if(len<=3){
        cout<<(mn/4)*(mn/4+1)/2<<'\n';
        return ;
    }
    for(int i=1;i<=4;i++){
        for(int j=i+1;j<=4;j++){
            int num=abs(a[j]-a[i]);
            for(int k=1;k*k<=num;k++){
                if(num%k!=0) continue;
                if(k*4>mn) break;
                if(chk(k)) s.insert(k);
                if((num/k)*4<=mn && chk(num/k)) s.insert(num/k);
            }
        }
    }
    int ans=0;
    for(auto i:s) ans+=i;
    cout<<ans<<'\n';
}
posted @ 2025-11-13 21:40  香香的鸽子  阅读(3)  评论(0)    收藏  举报