1 条题解

  • 0
    @ 2026-10-26 15:31:29

    思路与算法

    令f[t][s]为用集合S数字构成t位串的数位和计数,用逐位加数字的背包递推得到f,设G(t)=Σs f[t][s]^2。前后半和相同与奇偶位和相同各有G(n)种,需减交集。把2n位置按前后半和奇偶分成四块,两等式相加减得到对角块数字和分别相等;块长为floor(n/2)和ceil(n/2),交集为G(floor(n/2))G(ceil(n/2))。

    正确性说明

    f的转移按最后一位唯一拆分。相同长度两块和相等的方案数对每个和独立相乘,求和即G。四块分类把两条件同时成立严格等价为两对独立和相等,交集乘积成立;容斥给并集2G(n)-交集。

    复杂度

    滚动DP初始化O(n),逐长度处理至9t的和并枚举至多10个数字,总O(|S|n²)时间,G计算O(n²);空间O(n)(和数组长度9n+1),模999983。

    易错点

    允许前导0;S是集合,输入顺序无关。n奇数时四块不是同长,应分别取下整和上整。

    参考代码(C++11)

    #include <bits/stdc++.h>
    using namespace std;
    const int MOD = 999983;
    int main() {
        int n;
        string s;
        cin >> n >> s;
        vector<int> d;
        for (char c : s)
            d.push_back(c - '0');
        sort(d.begin(), d.end());
        d.erase(unique(d.begin(), d.end()), d.end());
        vector<int> a(9 * n + 1), b(9 * n + 1), S(n + 1);
        a[0] = 1;
        S[0] = 1;
        for (int k = 1; k <= n; k++) {
            fill(b.begin(), b.end(), 0);
            for (int x = 0; x <= 9 * (k - 1); x++)
                if (a[x])
                    for (int z : d) {
                        b[x + z] += a[x];
                        if (b[x + z] >= MOD)
                            b[x + z] -= MOD;
                    }
            a.swap(b);
            long long sum = 0;
            for (int x = 0; x <= 9 * k; x++)
                sum = (sum + 1LL * a[x] * a[x]) % MOD;
            S[k] = sum;
        }
        cout << (2LL * S[n] - 1LL * S[n / 2] * S[(n + 1) / 2] % MOD + MOD) % MOD << '\n';
    }
    
    • 1

    信息

    ID
    1797
    时间
    1000ms
    内存
    128MiB
    难度
    普及+
    标签
    递交数
    1
    已通过
    1
    上传者