1 条题解

  • 0
    @ 2026-10-31 17:57:26

    思路

    题意:有 nn 个信号强度 aia_i 和周期长度 mm,信号按规则分入 mm 个频段,规则保证“强度相差 mm 的整数倍的两个信号落进同一频段”。求信号数最多的频段里有多少个信号。

    把“频段”翻译成取模

    题面只说明了充分条件:ai≡aj(modm)⇒a_i \equiv a_j \pmod m \Rightarrow 同一频段。而频段总数为 mm,且编号由强度在长度为 mm 的周期内的位置决定,因此频段编号就是 ai mod ma_i \bmod m 这一余数类:

    • 余数相同 ⇒ 差是 mm 的倍数 ⇒ 必在同一频段;
    • 余数不同 ⇒ 差不是 mm 的倍数 ⇒ 不可能同频段(mm 个余数恰好对应 mm 个频段)。

    所以问题转化为:统计所有 ai mod ma_i \bmod m 的出现次数,输出最大值。

    实现

    1. 读入 n,mn, m,用 map<int,int> 记录每个余数出现的次数:cnt[x % m]++;
    2. 由于 ai≥1a_i \ge 1,取模不会出现负数,无需额外修正;
    3. 遍历 map 中所有键值对,取最大的计数作为答案。

    用 map 而不是长度为 mm 的数组,是因为 mm 可能远大于 nn,数组会浪费空间;map 的实际条目数不超过 nn。cnt 定义在 go() 内部,因此每组测试自动清空。

    复杂度

    每组数据时间 O(nlog⁡n)O(n \log n)(map 插入与遍历),空间 O(n)O(n)。题目保证 ∑n≤105\sum n \le 10^5,完全够用。

    代码

    #include<bits/stdc++.h>
    #define int long long
    #define dd double
    #define str string
    #define el cout << '\n'
    #define re return
    #define ff first
    #define ss second
    #define pll pair<int,int>
    #define pdd pair<dd,dd>
    #define all(x) x.begin(),x.end()
    #define pb push_back
    using namespace std;
    
    
    // 每组测试:统计各余数(频段)的信号数,输出最大值
    void go(){
        int n, m;cin>>n>>m;
        map<int, int>cnt;       // 键为余数(即频段编号),值为该频段的信号数
        for(int i=1;i<=n;i++){
            int x;cin>>x;
            cnt[x%m]++;         // a_i >= 1,取模结果非负,直接作为频段编号
        }
    
        // 取所有频段中信号数的最大值
        int ans = 0;            // 信号数最多的频段所包含的信号数
        for(auto [num, c]:cnt){
            ans = max(ans, c);
        }
    
        cout<<ans;el;           // 输出最大信号数
    }
    
    signed main() {
        ios::sync_with_stdio(false);
        cin.tie(nullptr);cout.tie(nullptr);
        int _=1;
        cin >>_;               // 读入测试组数 T
        while(_--){
            go();
        }
        return 0;
    }
    
    • 1

    信息

    ID
    41
    时间
    1000ms
    内存
    256MiB
    难度
    4
    标签
    递交数
    0
    已通过
    0
    上传者