• [HAOI2008]硬币购物-题解


    传送门

    解答

    根据容斥原理

    [left|igcap_{i=1}^n overline{S_i} ight| = |U| - left|igcup_{i=1}^n S_i ight| = sum_{0 le kle n}(-1)^ksum_{1le i_1<cdots<i_kle n}left|igcap_{j=1}^k S_{i_j} ight| ]

    其中(S_i)表示第(i)种元素超限的取的方法集合,交的初始值是(U)。((U)表全集,(overline A)(A)(U)下的补集)

    如何求出(left|igcap_{j=1}^k S_{i_j} ight|)
    考虑先求出完全背包的dp值
    然后强制将第(i_j)个元素选取超过(d_{i_j})个。
    这样的方案总数为(dp[t]-dp[t-sum_{j=1}^k(d_i+1)c_i])。((dp[])的负数项为(0)

    然后就可以愉快地容斥了。

    #include <bits/stdc++.h>
    using namespace std;
    
    const int n = 4, mx = 1e5+10, pm[] = {1,-1};
    #define int long long
    
    int c[n], d[n], dp[mx] = {1};
    
    signed main() {
    	for (int i = 0; i < 4; ++i) {
    		cin >> c[i];
    		for (int j = c[i]; j < mx; ++j)
    			dp[j] += dp[j-c[i]];
    	}
    	int tot, s;
    	cin >> tot;
    	while (tot--) {
    		for (int i = 0; i < 4; ++i) cin >> d[i];
    		cin >> s;
    		int res = 0;
    		for (int i = 0; i < 16; ++i) {
    			int tmp = s, cnt = 0;
    			for (int j = 0; j < 4; ++j) {
    				if ((i>>j) & 1) {
    					cnt++;
    					tmp -= (d[j]+1)*c[j];
    				}
    			}
    //			cout << cnt << ' ' << tmp << endl;
    			res += pm[cnt%2]*(tmp>=0?dp[tmp]:0);
    		}
    		cout << res << endl;
    	}
    }
    
    
  • 相关阅读:
    Repository Pattern with Entity Framework 4.1 and Code First
    Entity Framework 4.1/4.3 之四(DBContext 之 1 DBContext 是谁)
    C# 依赖注入
    explicit关键字
    enum关键字
    #pragma once
    #if 0 #end if
    assert
    存储类型
    const关键字
  • 原文地址:https://www.cnblogs.com/topsecret/p/11626423.html
Copyright © 2020-2023  润新知