题意: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;
}