题意:
给出4种硬币的价值
q个询问 q<=1000
每次询问给出硬币的上限,跟需要组成的价值s<100000
问组成s有多少种方法
思路:
如果每次跑完全背包,最坏可能到O(qs)接受不能
先看成无硬币限制,算是经验题吧
然后ans=f【s】-f【1种硬币超限制】+f【2种硬币超限制】-f【3种硬币超限制】+f【4种硬币超限制】
#include<iostream> #include<stdio.h> #include<string.h> #define ll long long using namespace std; ll f[1000005]; int d[15]; int c[15]; int main() { memset(f,0,sizeof(f)); int c1,c2,c3,c4,tot; int d1,d2,d3,d4,s; for(int i=1;i<=4;i++)scanf("%d",&c[i]);//f[c[i]]++; scanf("%d",&tot); f[0]=1; for(int i=1;i<=4;i++) for(int j=1;j<=1000000;j++) if(j>=c[i]) f[j]+=f[j-c[i]]; //for(int i=1;i<=20;i++) printf("%d\n",f[i]); for(int k=1;k<=tot;k++) { for(int jj=1;jj<=4;jj++)scanf("%d",&d[jj]); scanf("%d",&s); ll ans=f[s]; for(int i=1;i<(1<<4);i++) { int cnt=0;ll tem=0; for(int j=0;j<4;j++) { if(i&(1<<j)) { tem+=(d[j+1]+1)*c[j+1]; cnt++; } } if(cnt%2==0) if(s>=tem)ans+=f[s-tem]; if(cnt%2==1) if(s>=tem)ans-=f[s-tem]; } printf("%lld\n",ans); } }