1 条题解

  • 0
    @ 2025-12-16 10:26:22

    这是一个为“连续子段的整除判定”题目设计的标准数据生成器。它包含了标准解法(用于生成.out文件)和数据生成逻辑(用于生成.in文件)。

    这份代码会直接在当前目录下生成 1.in/1.out10.in/10.out 共20个文件,覆盖了从小数据、边界情况(如0、长度不足)到大规模数据的完整测试场景。

    数据生成器策略说明

    为了保证测试数据的有效性,设计了以下10个测试点:

    1. TestCase 1 (Sample): 题目给出的样例,保证基础正确性。
    2. TestCase 2 (Small NO): 小规模数据,构造不存在解的情况。
    3. TestCase 3 (Zeros): 包含连续的 0,考察对 0 的处理(00 是任何 kk 的倍数)。
    4. TestCase 4 (Length Trap): 构造前缀和余数相同但距离为 1 的情况(如 [1, k, 2]),考察是否正确处理“长度至少为2”。
    5. TestCase 5 (Pigeonhole YES): N>KN > K,根据抽屉原理必然存在同余前缀和,考察大规模下的正确判定。
    6. TestCase 6 (Large NO - Constructed): 大规模数据,通过构造(如全为 1 且 K>NK > N)强行让结果为 NO。
    7. TestCase 7 (Large K): KK 非常大(接近 INT_MAX),考察哈希表和取模的性能。
    8. TestCase 8 (Random Big): N=105N=10^5, KN/2K \approx N/2,随机性较强。
    9. TestCase 9 (Max Values): 元素值很大(接近 10910^9),考察前缀和是否使用 long long 避免溢出。
    10. TestCase 10 (Max N & K): 极限数据,N=105N=10^5, K=2311K=2^{31}-1

    C++ 数据生成器代码

    请保存为 generator.cpp,编译运行即可。

    /**
     * 题目:连续子段的整除判定 - 数据生成器
     * 功能:生成 1.in/1.out ~ 10.in/10.out
     * 环境:C++14 Standard
     */
    
    #include <iostream>
    #include <fstream>
    #include <vector>
    #include <string>
    #include <random>
    #include <unordered_map>
    #include <algorithm>
    #include <chrono>
    
    using namespace std;
    
    // ==========================================
    // Part 1: 标准解法 (Solver)
    // 用于生成 .out 文件
    // ==========================================
    string solve(int n, long long k, const vector<long long>& nums) {
        if (n < 2) return "NO";
    
        // map: {remainder -> first_index}
        // 使用 unordered_map 保证 O(N)
        unordered_map<long long, int> mp;
        
        // 初始化:前缀和为0的情况,虚拟下标-1
        mp[0] = -1;
        
        long long currentSum = 0;
        
        for (int i = 0; i < n; ++i) {
            currentSum += nums[i];
            
            // 计算余数
            long long remainder = currentSum % k;
            
            if (mp.count(remainder)) {
                int prevIndex = mp[remainder];
                // 检查长度是否 >= 2
                if (i - prevIndex >= 2) {
                    return "YES";
                }
                // 如果长度 < 2,不更新下标,保留最左边的以获得更长子段
            } else {
                mp[remainder] = i;
            }
        }
        
        return "NO";
    }
    
    // ==========================================
    // Part 2: 数据生成工具
    // ==========================================
    mt19937_64 rng(chrono::steady_clock::now().time_since_epoch().count());
    
    // 生成随机整数 [min, max]
    long long randInt(long long min, long long max) {
        uniform_int_distribution<long long> dist(min, max);
        return dist(rng);
    }
    
    // 写入文件辅助函数
    void writeData(int caseId, int n, long long k, const vector<long long>& nums) {
        string inFileName = to_string(caseId) + ".in";
        string outFileName = to_string(caseId) + ".out";
        
        // 写入 .in
        ofstream inFile(inFileName);
        inFile << n << " " << k << endl;
        for (int i = 0; i < n; ++i) {
            inFile << nums[i] << (i == n - 1 ? "" : " ");
        }
        inFile << endl;
        inFile.close();
        
        // 计算并写入 .out
        string ans = solve(n, k, nums);
        ofstream outFile(outFileName);
        outFile << ans << endl;
        outFile.close();
        
        cout << "Generated Case " << caseId << ": N=" << n << ", K=" << k << " -> " << ans << endl;
    }
    
    // ==========================================
    // Part 3: 生成逻辑主体
    // ==========================================
    int main() {
        // --- 1. 样例数据 ---
        {
            int n = 5;
            long long k = 6;
            vector<long long> nums = {23, 2, 4, 6, 7};
            writeData(1, n, k, nums);
        }
    
        // --- 2. 小规模 NO ---
        {
            // 1, 2, 3, 4, 5 的前缀和是 1, 3, 6, 10, 15
            // K=100,余数都不重复
            int n = 5;
            long long k = 100;
            vector<long long> nums = {1, 2, 3, 4, 5};
            writeData(2, n, k, nums);
        }
    
        // --- 3. 包含0的情况 (Zeroes) ---
        {
            // 0是任何K的倍数,连续两个0必然YES,或者数和0组合
            int n = 10;
            long long k = 7;
            vector<long long> nums(n);
            for(int i=0; i<n; ++i) nums[i] = (i == 5 || i == 6) ? 0 : randInt(1, 10);
            writeData(3, n, k, nums);
        }
    
        // --- 4. 长度陷阱 (Length < 2) ---
        {
            // 构造:前缀和余数重复,但距离为1
            // 例如 K=10, 数组 [1, 10, 2]
            // Pre: 1 (idx 0), 11 (idx 1), 13 (idx 2)
            // Mods: 1, 1, 3
            // Mod 1 重复,indices: 0, 1 -> dist = 1 (Too short) -> NO
            int n = 3;
            long long k = 10;
            vector<long long> nums = {1, 10, 2};
            writeData(4, n, k, nums);
        }
    
        // --- 5. 抽屉原理 YES (N >= K) ---
        {
            // 当 N >= K 时,前缀和模K只有 K 种取值,N个前缀和必然有重复
            // 除非运气极差所有重复都是相邻的(概率极低),大概率 YES
            int n = 1000;
            long long k = 500;
            vector<long long> nums(n);
            for(int i=0; i<n; ++i) nums[i] = randInt(1, 1000);
            writeData(5, n, k, nums);
        }
    
        // --- 6. 构造大规模 NO ---
        {
            // 构造:让前缀和严格递增且 < K
            // 全是 1,K > N
            int n = 20000;
            long long k = 50000; 
            vector<long long> nums(n, 1);
            writeData(6, n, k, nums);
        }
    
        // --- 7. Large K (随机) ---
        {
            int n = 5000;
            long long k = 2000000000LL; // 2 * 10^9
            vector<long long> nums(n);
            for(int i=0; i<n; ++i) nums[i] = randInt(0, 100000);
            writeData(7, n, k, nums);
        }
    
        // --- 8. Random Big Data (YES/NO Mixed) ---
        {
            int n = 100000; // 10^5
            long long k = 7919; // 素数
            vector<long long> nums(n);
            for(int i=0; i<n; ++i) nums[i] = randInt(0, 10000);
            writeData(8, n, k, nums);
        }
    
        // --- 9. 大数值元素 (Max Values) ---
        {
            // 考察 long long 溢出(虽然题目保证前缀和在64位内,但生成时要注意)
            // 题目数据范围 a_i <= 10^9
            int n = 50000;
            long long k = 1234567;
            vector<long long> nums(n);
            for(int i=0; i<n; ++i) nums[i] = randInt(100000000, 1000000000);
            writeData(9, n, k, nums);
        }
    
        // --- 10. 极限数据 (Max Constraints) ---
        {
            int n = 100000;
            long long k = 2147483647LL; // INT_MAX
            vector<long long> nums(n);
            // 这里随机生成,由于 K 很大,可能是 NO,也可能是 YES(取决于随机碰撞)
            for(int i=0; i<n; ++i) nums[i] = randInt(0, 1000000000);
            writeData(10, n, k, nums);
        }
    
        cout << "All 10 test cases generated successfully!" << endl;
        return 0;
    }
    

    使用指南

    1. 编译:
      g++ generator.cpp -o generator -std=c++14 -O2
      
    2. 运行: Windows下直接双击 generator.exe 或命令行运行 generator。 Linux/Mac下运行 ./generator
    3. 结果: 程序运行后,你的文件夹中会出现 1.in ~ 10.in 以及对应的答案 1.out ~ 10.out
    4. 注意:
      • 代码中使用了 <random>std::mt19937_64 确保随机数质量。
      • solve 函数已针对题目逻辑进行了完整实现,包括对 00 的处理和长度限制的处理。
      • TestCase 6 特意构造了全为 1 且 N<KN < K 的情况,确保生成一个大规模的 NO 数据,防止随机数据全是 YES
    • 1

    信息

    ID
    19327
    时间
    1000ms
    内存
    32MiB
    难度
    10
    标签
    (无)
    递交数
    1
    已通过
    1
    上传者