• BZOJ5302 [HAOI2018]奇怪的背包 【数论 + dp】


    题目

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

    输入格式

    从文件 knapsack.inknapsack.in 中读入数据. 第一行三个整数 nn , qq , PP ,含义见问题描述. 接下来一行 nn 个整数表示 V_iV
    i
    ​ . 接下来一行 qq 个整数表示 w_iw
    i
    ​ .

    输出格式

    输出到文件 knapsack.outknapsack.out 中. 输出 qq 行,每行一个整数表示答案.

    输入样例

    3 3 6
    1 3 4
    5 2 3

    输出样例

    5
    6
    6

    提示

    题解

    考虑数论中的(ax + by)这样线性组合的形式,其只能表示(gcd(a,b))的倍数
    (ax mod P)可以写成(ax - Py),也是(a)(P)的线性组合
    所以一个物品只能表示(gcd(V[i],P))的倍数
    我们只需要求出所有(P)的约数的方案数,对于询问(W[i]),我们只需要查询(gcd(W[i],P))的倍数的方案数

    (f[i][j])表示前(i)个数凑出以约数(j)为线性组合中的最小值的方案数【即(j)对其倍数的贡献】,转移即可

    (10^9)以内约数最大不超过(10^3)

    建议别用STL

    #include<iostream>
    #include<cstdio>
    #include<cmath>
    #include<map>
    #include<cstring>
    #include<algorithm>
    #define LL long long int
    #define Redge(u) for (int k = h[u],to; k; k = ed[k].nxt)
    #define REP(i,n) for (int i = 1; i <= (n); i++)
    #define BUG(s,n) for (int i = 1; i <= (n); i++) cout<<s[i]<<' '; puts("");
    #define MAP map<int,int>
    #define res register 
    using namespace std;
    const int maxn = 1000005,maxm = 100005,INF = 1000000000,md = 1e9 + 7;
    inline int read(){
    	res int out = 0,flag = 1; res char c = getchar();
    	while (c < 48 || c > 57){if (c == '-') flag = -1; c = getchar();}
    	while (c >= 48 && c <= 57){out = (out << 3) + (out << 1) + c - 48; c = getchar();}
    	return out * flag;
    }
    inline void write(int x){if (x >= 10) write(x / 10); putchar(x % 10 + '0');}
    MAP f[2],Ans,A;
    MAP::iterator it,IT;
    int n,m,P;
    inline int add2(int x,int y){x += y; if (x >= md) x -= md; return x;}
    inline void add(int& x,int y){x += y; if (x >= md) x -= md;}
    inline int gcd(int a,int b){return b ? gcd(b,a % b) : a;}
    void init(){
    	int tmp,p = 1; f[0][P] = 1;
    	for (IT = A.begin(); IT != A.end(); IT++,p ^= 1){
    		f[p].clear();
    		for (it = f[p ^ 1].begin(); it != f[p ^ 1].end(); it++){
    			add(f[p][it->first],it->second);
    			tmp = gcd(IT->first,it->first);
    			add(f[p][tmp],1ll * add2(IT->second,md - 1) * it->second % md);
    		}
    	}
    	p ^= 1;
    	for (res int i = 1; 1ll * i * i <= P; i++) Ans[i] = Ans[P / i] = 0;
    	for (it = Ans.begin(); it != Ans.end(); it++)
    		for (IT = f[p].begin(); IT != f[p].end(); IT++)
    			if (it->first % IT->first == 0)
    				add(it->second,IT->second);
    }
    void solve(){
    	while (m--) write(Ans[gcd(read(),P)]),puts("");
    }
    int main(){
    	n = read(); m = read(); P = read();
    	int x;
    	for (res int i = 1; i <= n; i++){
    		x = gcd(read(),P);
    		if (!A.count(x)) A[x] = 2;
    		else A[x] = A[x] * 2 % md;
    	}
    	init();
    	solve();
    	return 0;
    }
    
    
  • 相关阅读:
    arpspoof局域网断网攻击
    2019-2020 SEERC 2019
    2019-2020 XX Open Cup, Grand Prix of Korea
    欧拉函数板子
    Syncthing – 数据同步利器
    程序员的修养 -- 如何写日志(logging)
    css基础
    vim永久设置主题
    基金选择
    如何查看ntp端口是否正常
  • 原文地址:https://www.cnblogs.com/Mychael/p/8969359.html
Copyright © 2020-2023  润新知