zoukankan      html  css  js  c++  java
  • Luogu P1450 [HAOI2008]硬币购物

    gate

    背包dp+容斥,然而没想出来。
    首先预处理出没有限制的方案数。
    价值为(c_i)的硬币有(d_i)个,那么不合法的方案数即为(f[c_i*(d_i+1)]),因为若(c_i)超出限制,后面的再怎么选都是不合法的了。
    但这样显然会有重复计算。所以,根据容斥原理,减去1种超限的,加上2种超限的,减去3种超限的,加上4种超限的。

    for(int i = 1; i <= 15; i++) {
    	k = 1;
    	now = 0;
    	for(int j = 1; j <= 4; j++)
    		if((i >> (j-1)) & 1) {
    			now += c[j]*(d[j]+1);
    			k *= -1;
    		}
    	if(now <= s)
    		sum += k * f[s-now];
    }
    

    用2进制表示状态,15=1111=四个都选。
    用一个数字k记录奇偶(正负)
    最后别忘了判断状态是否存在(now <= s),否则会re...

    完整代码如下

    #include<cstdio>
    #include<iostream>
    #include<cmath>
    #include<cstring>
    #define MogeKo qwq
    using namespace std;
    
    const int maxn = 1e5+10;
    
    int n,s,c[5],d[5];
    long long sum,k,now,f[maxn];
    
    int main() {
    	for(int i = 1; i <= 4; i++)
    		scanf("%d",&c[i]);
    	f[0] = 1;
    	for(int i = 1; i <= 4; i++)
    		for(int j = c[i]; j <= 100000; j++)
    			f[j] += f[j-c[i]];
    	scanf("%d",&n);
    	while(n--) {
    		for(int i = 1; i <= 4; i++)
    			scanf("%d",&d[i]);
    		scanf("%d",&s);
    		sum = f[s];
    		for(int i = 1; i <= 15; i++) {
    			k = 1;
    			now = 0;
    			for(int j = 1; j <= 4; j++)
    				if((i >> (j-1)) & 1) {
    					now += c[j]*(d[j]+1);
    					k *= -1;
    				}
    			if(now <= s)
    				sum += k * f[s-now];
    		}
    		printf("%lld
    ",sum);
    	}
    	return 0;
    }
    
  • 相关阅读:
    凹透镜
    三角形动点和将军饮马
    数学
    壮壮学习准则
    均值不等式,求极值
    2020年自贡中考数学真题,用的是花钱买的"几何画板",wechat:QZCS12
    90年高考题
    裂项:2005年初中数学竞赛题p32,4
    02-需求来源
    01-产品需求的内涵
  • 原文地址:https://www.cnblogs.com/mogeko/p/12984672.html
Copyright © 2011-2022 走看看