zoukankan      html  css  js  c++  java
  • [haoi2008]硬币购物

    描述 Description
    一共有4种硬币,面值分别为c1,c2,c3,c4. 阿Q带着一些硬币去商店买东西,他带了d1枚第一种硬币,d2枚第二种硬币,d3枚第三种硬币,d4枚第四种硬币,若想买一个价值为s的东西,问阿Q有多少种付coins的方法.
    比如c={1,2,5,10},d={3,2,3,1},s=10,一共有4种方法:
    10=1+1+1+2+5
    10=1+2+2+5
    10=5+5
    10=10
    注意,阿Q可能会去很多次商店,每次带的硬币数量和要买的东西价值可能不一样,你需要对每一次都求出方法总数。

    输入格式 Input Format
    输入第一行是5个正数c1,c2,c3,c4,tot,分别表示4种硬币的面值和阿Q去商店的次数,接下来tot行,每行5个非负整数,d1,d2,d3,d4,s.

    输出格式 Output Format
    输出有tot行,表示第i次付coins的方法总数,保证答案在int64/long long范围内. 

    样例输入 Sample Input
    1 2 5 10 2
    3 2 3 1 10
    1000 2 2 2 900

    样例输出 Sample Output
    4
    27 

    时间限制 Time Limitation
    1s 

    注释 Hint
    数据范围
    100%的测试数据, d1,d2,d3,d4,s <=100000.
    30%的测试数据, tot<=50.
    100%的测试是数据, tot<=1000.

    来源 Source
    haoi2008  

          虽说haoi日常出一些**的题目,但这道题用来练一下容斥还是蛮不错的。一个值得思考一下的题。

       因为s最大就为100000,最多也就4中硬币,所以你可以开一个数组把所有可以得到的总硬币面值的情况记录下来。然后利用容斥的思想用无限制的总数减去超出限制的数量就等于方案数。具体:先减去单个超过限制的方案,在加上两两超过限制的方案数,因为在你减去单个方案数的时候重复减了(容斥原理)然后挨着减就好了,最后再把4个超过限制加起来就好了

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cmath>
    #include<cstring>
    using namespace std;
    int c[5],t,d[5];
    long long f[110000];
    long long ans=0;
    int main()
    {
        for(int i=1;i<=4;i++)
            cin>>c[i];
        cin>>t;
        f[0]=1;
        for(int i=1;i<=4;i++)
            for(int j=c[i];j<=100000;j++)
                f[j]+=f[j-c[i]];
        for(int i=1;i<=t;i++)
        {
            for(int j=1;j<=4;j++)
                cin>>d[j];
            int s;
            cin>>s;
            ans=f[s];
            for(int j=1;j<=4;j++)
            {
                int h=s-c[j]*(d[j]+1);
                if(h>=0)
                    ans-=f[h];
            }
            for(int j=1;j<=4;j++)
            {
                for(int k=j+1;k<=4;k++)
                {
                    int h=s-c[j]*(d[j]+1)-c[k]*(d[k]+1);
                    if(h>=0)
                        ans+=f[h];
                }
            }
            int h=0;
            for(int j=1;j<=4;j++)
            {
                h=0;
                for(int k=1;k<=4;k++)
                    if(j!=k)
                        h+=(c[k]*(d[k]+1));
                if(s-h>=0)
                    ans-=f[s-h];
            }
            int y=s-(h+c[4]*(d[4]+1));
            if(y>=0)
                ans+=f[y];
            cout<<ans<<endl;
        }
        return 0;
    }

      

  • 相关阅读:
    10465
    移动Web开发图片自适应两种常见情况解决方案
    [置顶] Spring的DI依赖实现分析
    Android中两种设置全屏或者无标题的方法
    Esper系列(十二)Variables and Constants
    Esper系列(十一)NamedWindow语法Merge、Queries、Indexing、Dropping
    Esper系列(十)NamedWindow语法delete、Select+Delete、Update
    Esper系列(九)NamedWindow语法create、Insert、select
    Esper系列(八)Method Definition、Schema
    Docker系列(五)OVS+Docker网络打通示例
  • 原文地址:https://www.cnblogs.com/lcyhaha/p/7611862.html
Copyright © 2011-2022 走看看