Codechef APRIL14 ANUCBC Cards, bags and coins 题解

  题目大意

    有n个数字,选出一个子集,有q个询问,求子集和模m等于0的方案数%1000000009。(n <= 100000,m <= 100,q <= 30)

  假设数据很小,我们完全可以做一个背包。

  我们沿着背包的思路,看能不能给物品分一下类,由于m比较小,完全按N个数字模M后的值进行分类,这样就变成了一个多重背包的问题。(转移时要乘上一个组合数)

  这时候的时间复杂度是n*m,还是不能过。

  对于DP时所枚举到的模m后余数j,它所进行的状态转移是一定的,如果把这些转移先预处理出来,时间复杂度就能得到有效减小。

  分析一下,转移方程是 F[i][j] = sigma(F[i][(j-i*k+m)%m]*C(count[i], k))%MOD,可以发现,(j-i*k+m)%m的值最多也只有m个,根本不需要枚举count[i]个这么多。

  设t = (i*k)%m,G[i][t] = sigma(C(count[i], k)) (k = 0..count[i] 且 i*k%m == t),G数组可以在O(n)的时间内预处理出来。

  新的转移方程就可以整理为 F[i][j] = sigma(F[i][(j-t+m)%m]*G[i][t])%MOD。 总的时间复杂度为O(n+m^3)。

  问题还没有结束,G数组的计算也需要一定的技巧。如果计算每个G[i][t]的值都算一次逆元和组合数,时间复杂度起码要加上一个log,会TLE。

  仔细分析可以发现,所计算的组合数C(count[i], k) (k = 0..count[i]),k是严格递增的,设temp = C(count[i], k-1),则C(count[i], k) = temp*(count[i]-(k-1))*inv[k]。

  inv数组可以利用逆元打表O(n)的方法来实现,具体可参考博文:http://blog.csdn.net/guhaiteng/article/details/52123385

  程序对拍过,但运行速度较慢。

  

#include <cstdio>
#include <cstring>

using namespace std;

typedef long long LL;
const int maxn = 100005;
const int MOD = 1000000009;
int n, m, Q;
int ccount[105];
LL g[105][105], inv[maxn], f[105][105];
int a[maxn], ans;

void add(LL &x, LL y)
{
    x += y;
    if (x >= MOD)
        x -= MOD;
}

void prepare()
{
    for (int i = 0; i < m; ++i)
        ccount[i] = 0;
    for (int i = 1; i <= n; ++i)
    {
        int temp = (a[i]%m+m)%m;
        ccount[temp] ++;
    }
    for (int i = 0; i < m; ++i)
        for (int j = 0; j < m; ++j)
            g[i][j] = 0;
    for (int i = 0; i < m; ++i)
    {
        LL temp = ccount[i];
        add(g[i][0], 1);
        add(g[i][i%m], ccount[i]);
        for (int j = 2; j <= ccount[i]; ++j)
        {
            (temp *= (ccount[i]-(j-1))) %= MOD;
            (temp *= inv[j]) %= MOD;
            add(g[i][(i*j)%m], temp);
        }
    }
}

void dp()
{
    memset(f, 0, sizeof(f));
    f[0][0] = g[0][0];
    for (int i = 1; i < m; ++i)
        for (int j = 0; j < m; ++j)
            for (int k = 0; k < m; ++k)
            {
                LL temp = f[i-1][(j-k+m)%m]*g[i][k]%MOD;
                add(f[i][j], temp);
            }
    ans = f[m-1][0];
}

int main()
{
    inv[1] = 1;
    for (int i = 2; i <= 100000; ++i)
        inv[i] = LL(MOD-MOD/i)*inv[MOD%i]%MOD;
    int Task;
    scanf("%d", &Task);
    while (Task --)
    {
        scanf("%d %d", &n, &Q);
        for (int i = 1; i <= n; ++i)
            scanf("%d", &a[i]);
        while (Q --)
        {
            scanf("%d", &m);
            prepare();
            dp();
            printf("%d\n", ans);
        }
    }
    return 0;
}
时间: 2024-10-17 04:47:52

Codechef APRIL14 ANUCBC Cards, bags and coins 题解的相关文章

[CC-ANUCBC]Cards, bags and coins

[CC-ANUCBC]Cards, bags and coins 题目大意: 给你\(n(n\le10^5)\)个数,\(q(q\le30)\)次询问,问从中选取若干个数使得这些数之和为\(m(m\le100)\)的方案数. 思路: 不难想到一个比较暴力的动态规划,用\(f[i][j]\)表示用了前\(i\)个数,和为\(j\)的方案数.时间复杂度\(\mathcal O(nmq)\). 发现动态规划中我们只关心每个数在模\(m\)意义下的值,因此直接用\(n\)个数转移实在是太愚蠢了. 将这些

codechef - Bytelandian gold coins 题解

In Byteland they have a very strange monetary system. Each Bytelandian gold coin has an integer number written on it. A coin n can be exchanged in a bank into three coins: n/2, n/3 and n/4. But these numbers are all rounded down (the banks have to ma

CodeChef--Cards, bags and coins

题目链接 Yet another game from chef. Chef gives you N cards and M bags. Each of the N cards has an integer written on it. Now chef asks you to close your eyes and choose a subset of them. He then sums the numbers written on chosen cards, takes its absolu

十二、背包问题

12.1 0/1 背包问题 12.1.1 题目模型 有 N 件物品和一个容量为 V 的背包.第 i 件物品的体积是 v[i] ,价值是 cost[i].求解将哪些物品装入背包可使价值总和最大. 12.1.2 基本思路 这是最基础的背包问题,特点是:每种物品仅有一件,可以选择放或不放. 用子问题定义状态:即 f[i][j] 表示前 i 件物品恰放入一个容量为 j 的背包可以获得的最大价值.则其状态转移方程便是:f[i][j]=max{f[i-1][j],f[i-1][j-v[i]]+cost[i]

Codechef July Challenge 2014部分题解

Dish Owner(并查集) 链接:http://www.codechef.com/JULY14/problems/DISHOWN/ 题意分析:本题主要操作就是给出0 x y时,拥有第x道菜的厨师与拥有第y道菜的厨师pk,谁拥有的所有菜的其中一道菜(不一定是x或y)的分值比较高谁就获胜,并赢得loser的所有菜.即比较的是每个人分值最高的菜,所以对于非loser的人来说,他的分值最高的菜是不变的.综合题意用并查集易解. #include <cstdio> const int Maxn=100

codechef Row and Column Operations 题解

You are given an N × N grid initially filled by zeros. Let the rows and columns of the grid be numbered from1 to N, inclusive. There are two types of operations can be applied to the grid: RowAdd R X: all numbers in the row R should be increased by X

Codechef Nuclear Reactors 题解

There are K nuclear reactor chambers labelled from 0 to K-1. Particles are bombarded onto chamber 0. The particles keep collecting in the chamber 0. However if at any time, there are more than N particles in a chamber, a reaction will cause 1 particl

codechef Cleaning Up 题解

After a long and successful day of preparing food for the banquet, it is time to clean up. There is a list of n jobs to do before the kitchen can be closed for the night. These jobs are indexed from 1 to n. Most of the cooks have already left and onl

codechef Permutation Cycles 题解

We consider permutations of the numbers 1,..., N for some N. By permutation we mean a rearrangment of the number 1,...,N. For example 2  4  5  1  7  6  3  8 is a permutation of 1,2,...,8. Of course, 1  2  3  4  5  6  7  8 is also a permutation of 1,2