1600+人过的题排#32还不错嘿嘿
浴谷夏令营讲过的题,居然1A了
预处理出f[i]表示购买价值为i的东西的方案数
然后每次询问进行一次容斥,答案为总方案数-第一种硬币超限方案-第二种超限方案-第三种超限方案-第四种超限方案+第一种和第二种硬币超限方案+...
第i种硬币超限方案就是f[s-c[i]*(d[i]+1)],其他的类推一下就行了
#include<iostream> #include<cstring> #include<cstdlib> #include<cstdio> #include<algorithm> #define ll long long using namespace std; const int maxn=100010,inf=1e9; int n,mx; ll ans; int c[5],d[maxn][5],s[maxn]; ll f[maxn]; void read(int &k) { int f=1;k=0;char c=getchar(); while(c<'0'||c>'9')c=='-'&&(f=-1),c=getchar(); while(c<='9'&&c>='0')k=k*10+c-'0',c=getchar(); k*=f; } void dfs(int fir,int dep,int sum,int last) { for(int i=last;i<=4;i++) { if(sum+c[i]*(d[fir][i]+1)>s[fir])continue; if(dep&1)ans-=f[s[fir]-sum-c[i]*(d[fir][i]+1)]; else ans+=f[s[fir]-sum-c[i]*(d[fir][i]+1)]; dfs(fir,dep+1,sum+c[i]*(d[fir][i]+1),i+1); } } int main() { for(int i=1;i<=4;i++)read(c[i]);read(n); for(int i=1;i<=n;i++) { for(int j=1;j<=4;j++)read(d[i][j]); read(s[i]);mx=max(mx,s[i]); } f[0]=1; for(int i=1;i<=4;i++) for(int j=c[i];j<=mx;j++) f[j]+=f[j-c[i]]; for(int i=1;i<=n;i++) { ans=f[s[i]]; dfs(i,1,0,1); printf("%lld ",ans); } return 0; }