[HAOI2008]硬币购物

[HAOI2008]硬币购物

https://ac.nowcoder.com/acm/problem/19974

分析

背包 题。因为朴素的 的时间复杂度为 应该过不去。那么换种思路,先考虑没有个数限制,令 为考虑前 种物品,体积为 时,总的方案数。发现我们对个数的限制可以考虑子集容斥。考虑到,恰好选 个的方案数是等于至少选 个的方案数减去至少选 的方案数。那么现在是让我们求恰好选 个的方案数,左式求个和,那么右式错位相消,那么至多选 的方案数为 ,最后考虑下一种的时候直接递归,要注意容斥系数也要变符号,时间复杂度为

  • 计算时可以滚动数组优化一下空间。
  • 要想到恰好选 个的方案数是等于至少选 个的方案数减去至少选 的方案数。这道题就不难了。

    代码

    #include<bits/stdc++.h>
    using namespace std;
    #define LL long long
    LL read() {
      LL x = 0,f = 0;char ch = getchar();
      while(!isdigit(ch)) {if(ch == '-')f=1;ch=getchar();}
      while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();}
      return f?-x:x;
    }
    const int N = 101000,M = 100000;
    LL c[5],tot,d[5],f[N],s,ans;
    void solve(LL i,LL S,LL opt) {
      if(S < 0) return;
      if(i == 5) {ans = (ans + opt * f[S]);return;};
      solve(i+1,S,opt);solve(i+1,S-((d[i] + 1)*c[i]),-1 * opt);
    }
    int main() { 
      f[0] = 1;
      for(int i = 1;i <= 4;i++) {
          c[i] = read(); 
          for(int j = c[i];j <= M;j++) f[j] = f[j] + f[j - c[i]]; 
      }
      tot = read();
      while(tot--) {
          for(int i = 1;i <= 4;i++) d[i] = read();
          s = read();ans = 0;
          solve(1,s,1);
          printf("%lld\n", ans);
      }
    }
    

```

数学 文章被收录于专栏

关于多项式

全部评论

相关推荐

11-01 08:48
门头沟学院 C++
伤心的候选人在吵架:佬你不要的,能不能拿户口本证明过户给我。。球球了
点赞 评论 收藏
分享
把球:这个听过,你加了就会发现是字节的hr
点赞 评论 收藏
分享
4 1 评论
分享
牛客网
牛客企业服务