zoukankan      html  css  js  c++  java
  • AtCoder Beginner Contest 182 F

    F - Valid payments

    简化题意:有(n)种面值的货币,保证(a[1]=1,且a[i+1]是a[i]的倍数)
    有一个价格为(x)元的商品,付款(y)元,找零(y-x)元。
    问满足以下条件的情况下的应支付金额(y)有多少种?
    条件一:付款和找零都使用最少的硬币数量。
    条件二:在满足条件一的情况下,付款是用过的硬币面值,找零时无法使用。
    考虑这个题对于条件一而言,可以归结为第(i)个硬币食用的个数不能超过(a[i+1]/a[i]),否则的话我们直接使用(a[i+1])会更优。这样的话在条件一的情况下,每个金额(x)都有唯一的表示方法:(x=k_{x1}*a_1+k_{x2}*a_2+k_{x3}*a_3+...+k_{xn}*a_n),这样的话我们令(b=y-x),则对于条件二而言限制条件就变成了(k_{yi}和k_{bi})不能同时非零,即不能同时使用。
    这样的话我们可以列出以下等式:
    (x=k_{x1}*a_1+k_{x2}*a_2+...+k_{xn}*a_n)
    (+b=k_{b1}*a_1+k_{b2}*a_2+...+k_{bn}*a_n)
    (y=k_{y1}*a_1+k_{y2}*a_2+...+k_{yn}*a_n)
    限制条件如下:(k_i不能超过a[i+1]/a[i]),且(k_{yi})(k_{bi})不能同时非零。问不同的(y),或(b)的方案数?(可以发现(y)(b)是一一对应的。)
    由于(k_{yi})(k_{bi})不能同时非零,则至少一个为(0),所以我们直接分类讨论就行:
    1.若(k_{yi})为0,则说明我们这里(k_{xi})(k_{bi})相加的和必须也为0,但这怎么可能呢?考虑会不会是进位的问题呢?什么意思就是我的(k_{xi})(k_{bi})都不超过(a[i+1]/a[i])但我的和却超过它了,这样的话就可以用前面的替代了。那么这样的话也就是必须满足(k_{xi}+k_{bi}+上一位的进位=a[i+1]/a[i]).这样的话才能满足当前位为(0).
    2.若(k_{bi})为0,说明(x_{ki}+上一位的进位=y_{ki})
    也就是说只要我们知道上一位是否进位,我们就可以根据当前(x_{ki})来确定当前不同情况下的y和b了。具体的就是我们设(dp[i][0/1])表示前(i)位,并且第(i)位进位/不进位的方案数。
    则根据情况二有:(dp[i][0]+=dp[i-1][0],dp[i][0]+=dp[i-1][1](k_{xi}!=a[i+1]/a[i]-1))
    根据情况一有:(dp[i][1]+=dp[i-1][1],dp[i][1]+=dp[i-1][0](k_{xi}!=0))
    由于金额最大的没有限定的使用数量,但我们发现(k_{bn})只能为0.

    //不等,不问,不犹豫,不回头.
    #include<bits/stdc++.h>
    #define _ 0
    #define ls p<<1
    #define db double
    #define rs p<<1|1
    #define P 1000000007
    #define ll long long
    #define INF 1000000000
    #define get(x) x=read()
    #define PLI pair<ll,int>
    #define PII pair<int,int>
    #define ull unsigned long long
    #define put(x) printf("%d
    ",x)
    #define putl(x) printf("%lld
    ",x)
    #define rep(x,y,z) for(int x=y;x<=z;++x)
    #define fep(x,y,z) for(int x=y;x>=z;--x)
    #define go(x) for(int i=link[x],y=a[i].y;i;y=a[i=a[i].next].y)
    using namespace std;
    const int N=110;
    ll n,x,a[N],mx[N],kx[N],dp[N][2];
    
    inline ll read()
    {
        ll x=0,ff=1;
        char ch=getchar();
        while(!isdigit(ch)) {if(ch=='-') ff=-1;ch=getchar();}
        while(isdigit(ch)) {x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
        return x*ff;
    }
    
    int main()
    {
        //freopen("1.in","r",stdin);
    	get(n);get(x);
    	rep(i,1,n) get(a[i]);
    	rep(i,1,n-1) mx[i]=a[i+1]/a[i];
    	fep(i,n,1)
    	{
    		if(x>=a[i])
    		{
    			kx[i]=x/a[i];
    			x-=kx[i]*a[i];
    		}
    	}
    	dp[0][0]=1;
    	rep(i,1,n)
    	{
    		dp[i][0]+=dp[i-1][0];
    		dp[i][1]+=dp[i-1][1];
    		if(kx[i]!=mx[i]-1) dp[i][0]+=dp[i-1][1];
    		if(kx[i]!=0) dp[i][1]+=dp[i-1][0];
    	}
    	putl(dp[n][0]);
        return (0^_^0);
    }
    //以吾之血,铸吾最后的亡魂.
    
    
  • 相关阅读:
    通过HttpListener实现简单的Http服务
    WCF心跳判断服务端及客户端是否掉线并实现重连接
    NHibernate初学六之关联多对多关系
    NHibernate初学五之关联一对多关系
    EXTJS 4.2 资料 跨域的问题
    EXTJS 4.2 资料 控件之Grid 那些事
    EXTJS 3.0 资料 控件之 GridPanel属性与方法大全
    EXTJS 3.0 资料 控件之 Toolbar 两行的用法
    EXTJS 3.0 资料 控件之 combo 用法
    EXTJS 4.2 资料 控件之 Store 用法
  • 原文地址:https://www.cnblogs.com/gcfer/p/15242261.html
Copyright © 2011-2022 走看看