zoukankan      html  css  js  c++  java
  • [HAOI2018]奇怪的背包

    Description

    (n) 种权值各不相同的物品,每种无穷个,给定数 (P)(q) 次询问,每次问有多少种选物品的方案(每种任意个),使得在模 (P) 意义下同余于 (w)。方案不同当且仅当物品种类不同。

    Solution

    容易知道(考虑裴蜀定理),对于一种价值为 (v) 的物品,使用无穷次后,得到的值只会是

    [0,gcd(v,P),2gcd(v,P),3gcd(v,P),dots ]

    所以考虑直接将 (v) 变为 (gcd(P,v))。进一步(多个数的裴蜀定理),对于多种物品,能凑出来的值有

    [0,gcd(v_1,v_2,dots),2gcd(v_1,v_2,dots),3gcd(v_1,v_2,dots),dots ]

    所以方案合法当且仅当 (gcd(v_1,v_2,dots)|w)
    容易发现 (gcd) 只会取 (P) 的约数,所以考虑算每种约数有多少种方案可以凑出。用 (dp[i][j]) 表示考虑了前 (i) 个约数,(gcd) 是第 (j) 个约数的方案。转移就很显然。
    算答案只需要枚举 (w) 的约数即可。但这样还是不够优秀。容易发现最终的答案其实是 (w)(P) 的高维前缀的交集。这个交集部分其实就是 (gcd(w,P)),而这一定是 (P) 的约数。所以可以考虑预处理高维前缀和。

    int main(){
        int n=read(),Q=read(),P=read(); pw[0]=1;
        for(int i=1;i*i<=P;i++)
            if(P%i==0){ p[++cnt]=i; if(i*i!=P) p[++cnt]=P/i;}
        sort(p+1,p+1+cnt); for(int i=1;i<=n;i++) pw[i]=pw[i-1]*2ll%Mod;
        for(int i=1;i<=n;i++)
            a[i]=gcd(read(),P),c[Get(a[i])]++;
        for(int i=1;i<=cnt;i++){
            for(int k=1;k<=cnt;k++){
                int &x=dp[Get(gcd(p[i],p[k]))];
                x=(x+1ll*dp[k]*(pw[c[i]]-1)%Mod)%Mod;
            }
            dp[i]=(dp[i]+pw[c[i]]-1)%Mod;
        }
        for(int i=cnt;i;i--)
            for(int j=1;j<i;j++)
                if(p[i]%p[j]==0) dp[i]=(dp[i]+dp[j])%Mod;
        while(Q--) printf("%d
    ",dp[Get(gcd(P,read()))]);
    }
    
  • 相关阅读:
    Django Rest Framework
    模块化开发
    单文件组件
    在create-react-app创建的React项目应用中配置JQ、Sass
    React 生命周期
    React项目的打包
    JS中的事件冒泡和事件捕获
    webpack 入门教程
    如何优雅地使用 VSCode 来编辑 vue 文件?
    页面跳转选中对应的导航
  • 原文地址:https://www.cnblogs.com/wwlwQWQ/p/15236636.html
Copyright © 2011-2022 走看看