• 奇怪的背包


    奇怪的背包

    有一个背包,有一个模数P,有n件物品,第i件物品体积为(v_i),物品可以无限取用,最后背包的体积为总体积(mod p),q组询问,第i个询问背包最终体积为(w_i)的方案数,两个方案数的不同不在于物品的放的个数,而在于物品是否取用。

    (n,qleq 10^6,pleq 10^9)

    显然物品的取用的次数没有关系,那么关键在于物品是否取用,以及它能到达的背包体积,于是对于一件物品不难写出式子

    [kv_i=z(mod p) ]

    k为取用的个数,z为得到的背包体积,于是由bezaut定理得知,它能所取用的背包的体积一定为(gcd(p,v_i))的倍数,而同理推广多个数自然为
    (gcd(v_1,v_2,...,v_n,p))的倍数。

    于是把各个(gcd(p,v_i))维护为(d[i]),个数为(s[j]),显然只有p的约数个数种,所以不难得知我们应设递推方程(f[i][j])表示选到第i件物品,现在最大公约数为(d[j])的方案数,现在暂时把n改成p的约数个数,所以又不难有

    [f[i][j]=f[i-1][j]+sum_{k=1}^nf[i-1][k] imes (gcd(d[k],d[i])==d[j])(2^{s[i]-1}) ]

    以此可以转移,于是对于询问我们的答案统计为

    [ans=sum_{j=1}^nf[j][w_i] ]

    注意到我们不能每次(sqrt{p})回答询问,于是我们设法维护出结果,(O(1))回答,显然暴力维护只有p的约数个数平方。

    参考代码:

    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #define il inline
    #define ri register
    #define ll long long
    #define yyb 1000000007
    #define _ putchar('
    ')
    #define swap(x,y) x^=y^=x^=y
    using namespace std;
    ll lsy,d[5000],dt,s[5000],cjx,
        bin[1000001],dp[2][5000],ask[5000];
    il void fact(ll);
    il int dfs(ll);
    il ll gcd(ll,ll);
    template<class free>void pen(free);
    template<class free>il void read(free&);
    int main(){
        int n,q,i,j;bool now(false);
        read(n),read(q),read(lsy),fact(lsy);
        for(i=bin[0]=1;i<=n;++i)read(cjx),++s[dfs(gcd(lsy,cjx))],
                                    bin[i]=(bin[i-1]<<1)%yyb;
        for(i=1;i<=dt;++i)s[i]=(bin[s[i]]+yyb-1)%yyb;
        for(i=1;i<=dt;++i,now^=1){
            dp[now][i]=s[i];
            for(j=1;j<=dt;++j)
                dp[now^1][j]=dp[now][j],
                    (dp[now^1][dfs(gcd(d[i+1],d[j]))]+=dp[now][j]*s[i+1])%=yyb;
        }
        for(i=1;i<=dt;++i)
            for(j=1;j<=i;++j)
                if(!(d[i]%d[j]))(ask[i]+=dp[now][j])%=yyb;
        while(q--)read(cjx),pen(ask[dfs(gcd(cjx,lsy))]),_;
        return 0;
    }
    il int dfs(ll x){
        int l(1),r(dt),mid;
        while(l<=r){
            mid=l+r>>1;
            if(d[mid]<x)l=mid+1;
            else r=mid-1;
        }return l;
    }
    il void fact(ll x){
        ll i;
        for(i=1;i*i<x;++i)
            if(!(x%i))d[++dt]=i,d[++dt]=x/i;
        if(i*i==x)d[++dt]=i;sort(d+1,d+dt+1);
    }
    template<class free>
    void pen(free x){if(x>9)pen(x/10);putchar(x%10+48);}
    il ll gcd(ll a,ll b){while(b)swap(a,b),b%=a;return a;}
    template<class free>
    il void read(free &x){
        x&=0;ri char c;while(c=getchar(),c<'0'||c>'9');
        while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+(c^48),c=getchar();
    }
    
  • 相关阅读:
    十进制,二进制,八进制,十六进制中的相互转换
    oracle中dual表的使用
    弹出窗口
    oracle中的函数
    [导入]几种所见所得的在线编辑器
    操作字符串
    设计模式初认识
    创建型模式之简单工厂模式
    MySQL批量检查表的脚本
    中英文单位对照
  • 原文地址:https://www.cnblogs.com/a1b3c7d9/p/10839825.html
Copyright © 2020-2023  润新知