洛谷P1450 [HAOI2008]硬币购物 背包+容斥

无限背包+容斥?


观察数据范围,可重背包无法通过,假设没有数量限制,利用用无限背包

进行预处理,因为实际硬币数有限,考虑减掉多加的部分

如何减?利用容斥原理,减掉不符合第一枚硬币数的,第二枚,依次类推

加上不符第一枚和第二枚的方案,第一枚和第三枚的方案以此类推,不明

白原理可以去看一下容斥原理

较长代码(懒得优化)

#include
#include
#include
#include
#define ll long long
using namespace std;
const int maxn=1e5+10;
inline int read(){
	int ret=0;
	int f=1;
	char ch=getchar();
	while(ch<'0'||ch>'9'){
		if(ch=='-')
			f=-f;
		ch=getchar();
	}
	while(ch<='9'&&ch>='0'){
		ret=ret*10+(ch^'0');
		ch=getchar();
	}
	return f*ret;
}
int c[5];
ll s;
ll dp[maxn];
int n;
ll ans;
ll d[5];
ll getn(int x){
	return (d[x]+1)*c[x];
} 
int main(){
//	freopen("a.txt","r",stdin);
	for(int i=1;i<=4;i++){
	//	c[i]=read();
	    cin>>c[i];
	}
	   cin>>n;
//	n=read();
//	cout<>d[i];
		}
	//	s=read();
	    cin>>s;
		ans=dp[s];
		for(int i=1;i<=4;i++){
			if(s>=getn(i)){
				ans-=dp[s-getn(i)];	
			}
		}
		if(s>=getn(1)+getn(2)){
			ans+=dp[s-getn(1)-getn(2)];
		}
		if(s>=getn(2)+getn(3)){
			ans+=dp[s-getn(2)-getn(3)];
		}
		if(s>=getn(3)+getn(4)){
			ans+=dp[s-getn(3)-getn(4)];
		}
		if(s>=getn(1)+getn(4)){
			ans+=dp[s-getn(1)-getn(4)];
		}
		if(s>=getn(2)+getn(4)){
			ans+=dp[s-getn(4)-getn(2)];
		}
		if(s>=getn(1)+getn(3)){
			ans+=dp[s-getn(1)-getn(3)];
		}
		if(s>=getn(1)+getn(2)+getn(3)){
			ans-=dp[s-getn(1)-getn(2)-getn(3)];
		}
		if(s>=getn(1)+getn(2)+getn(4)){
			ans-=dp[s-getn(1)-getn(2)-getn(4)];
		}
		if(s>=getn(1)+getn(3)+getn(4)){
			ans-=dp[s-getn(1)-getn(3)-getn(4)];
		}
		if(s>=getn(4)+getn(2)+getn(3)){
			ans-=dp[s-getn(4)-getn(2)-getn(3)];
		}
		if(s>=getn(1)+getn(2)+getn(3)+getn(4)){
			ans+=dp[s-getn(1)-getn(2)-getn(3)-getn(4)];
		}
		cout<

完结撒花

你可能感兴趣的:(洛谷P1450 [HAOI2008]硬币购物 背包+容斥)