1 条题解

  • 0
    @ 2025-5-13 0:15:47

    解题思路

    1. 初始化与预处理:读取糖果类型数量n、每种糖果的重量w[i]、查询数量m和每个查询的人数P[j]。计算所有糖果重量的最小公倍数W,以此作为状态表示的周期,初始化用于记录不同重量组合数量的数组f
    2. 动态规划计算组合数:利用动态规划的方法,根据糖果的重量和数量限制,计算在总重量为n*W范围内,每种重量对应的糖果盒组合数量,填充数组f
    3. 二分查找确定最小重量:对于每个查询的人数P[j],在一定重量范围内(最大为100 * P[j])进行二分查找。通过check函数检查当前重量k下,能否得到至少P[j]种不同的糖果盒组合。如果可以,则更新最小重量结果;如果遍历完所有可能重量都无法满足,则输出“no candy for you”。
    #include <iostream>
    #include <cstdlib>
    #include <cstdio>
    #include <algorithm>
    
    using namespace std;
    
    int n, w[10], W;
    long long f[200000];
    
    int gcd(int a, int b) {
        while (b) { int t = a % b; a = b; b = t; }
        return a;
    }
    
    bool check(long long k, int r, long long p) {
        long long tp;
        int i, j;
        for (i = 0; i < n; i++) {
            if (k < i) break;
            if (f[i * W + r] == 0) continue;
            tp = p / f[i * W + r];
            for (j = 1; j <= n - 1; j++)
                tp *= j;
            for (j = 1; j < n; j++)
                tp /= j + k - i;
            if (tp == 0) return true;
            tp = f[i * W + r];
            for (j = 1; j < n; j++)
                tp *= j + k - i;
            for (j = 1; j <= n - 1; j++)
                tp /= j;
            p -= tp;
        }
        return p == 0;
    }
    
    int main() {
        int m, i, j, k, t, u = 0, r;
        long long lt, rt, mt;
        long long sum, p, res;
        while (scanf("%d", &n), n) {
            u++;
            W = 1;
            for (i = 1; i <= n; i++) {
                scanf("%d", &w[i]);
                W = (W / gcd(W, w[i])) * w[i];  // Safer calculation to prevent overflow
            }
            
            for (i = 0; i < n * W; i++)
                f[i] = 0;
            f[0] = 1;
            for (i = 1; i <= n; i++) {
                if (w[i] == W) continue;
                for (r = 0; r < w[i]; r++) {
                    k = n * W - w[i] + r;
                    sum = 0;
                    for (j = w[i]; j < W; j += w[i])
                        sum += f[k - j];
                    f[k] += sum;
                    for (k -= w[i]; k >= 0; k -= w[i]) {
                        sum -= f[k];
                        if ((t = k + w[i] - W) >= 0)
                            sum += f[t];
                        f[k] += sum;
                    }
                }
            }
            printf("Set %d\n", u);
            scanf("%d", &m);
            while (m--) {
                scanf("%lld", &p);  // Correct format specifier for long long
                res = p * 100 + 1;
                for (r = 0; r < W; r++) {
                    lt = -1;
                    if (r == 0) lt++;
                    rt = (res - r) / W + 1;
                    while (lt + 1 < rt) {
                        mt = (lt + rt) >> 1;
                        if (check(mt, r, p))
                            rt = mt;
                        else
                            lt = mt;
                    }
                    if (res > rt * W + r) res = rt * W + r;
                }
                if (res > 100 * p)
                    puts("no candy for you");
                else
                    printf("%lld\n", res);  // Correct format specifier for long long
            }
        }
        return 0;
    }
    • 1

    信息

    ID
    1764
    时间
    1000ms
    内存
    256MiB
    难度
    10
    标签
    递交数
    16
    已通过
    1
    上传者