beginend

只要在路上,就没有到不了的远方

LibreOJ #2523.「HAOI2018」奇怪的背包 动态规划+数论

题意

C非常擅长背包问题,他有一个奇怪的背包,这个背包有一个参数P,当他向这个背包内放入若干个物品后,背包的重量是物品总体积对P取模后的结果.现在小Cn种体积不同的物品,第i种占用体积为Vi,每种物品都有无限个.他会进行q次询问,每次询问给出重量wi,你需要回答有多少种放入物品的方案,能将一个初始为空的背包的重量变为wi.注意,两种方案被认为是不同的,当且仅当放入物品的种类不同,而与每种物品放入的个数无关.不难发现总的方案数为2n。由于答案可能很大,你只需要输出答案对109+7取模的结果.
n,q106,P,Vi,wi109

分析

分析一波不难发现我们要求的就是有多少个集合满足gcd(Vi,P)|wi
先把所有的Vi变成gcd(Vi,P),所有的wi变成gcd(wi,P),然后把所有P的约数找出来。
显然P的约数个数是O(103)级别的。
那么我们对所有数进行dp,设f[i,j]表示前i个数中选出若干个,满足它们的gcd恰好为j的方案,然后就可以O(1)询问了。
时间复杂度O(σ2(P))

代码

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<cmath>

typedef long long LL;

const int N=2005;
const int MOD=1000000007;

int n,m,p,tot,w[N],id1[100005],id2[100005],bin[1000005],s[N],f[N][N],B,ans[N];

int gcd(int x,int y)
{
    if (!y) return x;
    else return gcd(y,x%y);
}

void pre()
{
    B=sqrt(p);
    for (int i=1;i*i<=p;i++)
        if (p%i==0)
        {
            w[++tot]=i;id1[i]=tot;
            if (p/i!=i) w[++tot]=p/i,id2[i]=tot;
        }
}

int main()
{
    scanf("%d%d%d",&n,&m,&p);
    pre();
    for (int i=1;i<=n;i++)
    {
        int x;scanf("%d",&x);
        x=gcd(x,p);
        if (x<=B) s[id1[x]]++;
        else s[id2[p/x]]++;
    }
    bin[0]=1;
    for (int i=1;i<=n;i++) bin[i]=bin[i-1]*2%MOD;
    f[0][id2[1]]=1;
    for (int i=0;i<tot;i++)
        for (int j=1;j<=tot;j++)
        {
            if (!f[i][j]) continue;
            (f[i+1][j]+=f[i][j])%=MOD;
            int x=gcd(w[i+1],w[j]),k=x<=B?id1[x]:id2[p/x];
            (f[i+1][k]+=(LL)f[i][j]*(bin[s[i+1]]-1)%MOD)%=MOD;
        }
    for (int i=1;i<=tot;i++)
        for (int j=1;j<=tot;j++)
            if (w[i]%w[j]==0) (ans[i]+=f[tot][j])%=MOD;
    while (m--)
    {
        int x;scanf("%d",&x);
        x=gcd(x,p);
        printf("%d\n",x<=B?ans[id1[x]]:ans[id2[p/x]]);
    }
    return 0;
}
阅读更多
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_33229466/article/details/80338646
个人分类: 动态规划 数论
想对作者说点什么? 我来说一句

杭电贪心算法,动态规划数论

2017年12月20日 154KB 下载

没有更多推荐了,返回首页

不良信息举报

LibreOJ #2523.「HAOI2018」奇怪的背包 动态规划+数论

最多只允许输入30个字

加入CSDN,享受更精准的内容推荐,与500万程序员共同成长!
关闭
关闭