1. 程式人生 > >Codeforces Round #493 (Div. 1) B

Codeforces Round #493 (Div. 1) B

題意:1,5,10,50四種硬幣不限量,問用剛好n個硬幣可以湊出多少種不同的數,n<=1e9

分析:本題的一大難點在於同一個數可能被不同的硬幣所表示,可以通過如下方法化簡:

由於硬幣數量固定,我們可以把所有硬幣的價值-1,使得價值變為{0,4,9,49}

考慮如果我們選了(49+x)個4或者9,可以將其換成x個4或9,將49的倍數部分用0和49進行填充

所以我們可以列舉4和9各選i,j個,i/j取[0,min(n,48)]之間且i+j<=n時可以得到的對於49的餘數

設sum = 4*i + 9*j, 剩下的位置只選擇0或49,可以在sum到sum+(n-i-j)*49之間每隔49個都能取一個

這樣對於每種49的餘數處理出最大的可行區間即可

#include<bits/stdc++.h>
#define pii pair<int, int>
#define fi first
#define se second
#define mk make_pair
#define sc(x) scanf("%d", &x)
#define pb push_back
#define ABS(x) ((x)<0?(-x):(x));
typedef long long LL;
using namespace std;
const int INF = 0x3f3f3f3f;
const int mod = 1e9+7;
const int maxn = 1e6+10;

int n, L[50], R[50];

int main(){
    freopen("lych.in", "r", stdin);
    for(int i = 0; i < 49; i++) L[i] = INF, R[i] = -INF;
    sc(n);
    L[0] = 0;
    R[0] = n;
    for(int i = 0; i <= min(n,49); i++){
        for(int j = 0; j <= min(n,49); j++){
            if(i+j > n) continue;
            int sum = (i*4+j*9);
            int r = sum%49, b = sum/49;
            L[r] = min(L[r], b);
            R[r] = max(R[r], b+n-i-j);
        }
    }
    LL ans = 0;
    for(int i = 0; i < 49; i++){
        if(L[i] >= INF) continue;
        //printf("L[%d]:%d, R[%d]:%d\n", i, L[i], i, R[i]);
        ans += R[i]-L[i]+1;
    }
    cout << ans << endl;
   return 0;
}