题意:一直都有0~300这300种价值的金额。
现在有n~1000次询问:
可能给出参数:
以下的n~300
1个:n, 输出可以组成价值n的方式的个数。
2个:n, a输出用硬币个数小于a的价值组成价值n的方式的个数。
3个:n, a, b输出用硬币个数大于a和小于b组成价值n的方式的个数。
题解:每次都要有个数的体现,那么就dp【300】【300】,一定不会多于300张,把张数作为第二维算进去。小细节,a和b为了避免数组越界,必须提前预判。
重点:需要张数从a到b,那么dp再开一维。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <cmath>
#include <ctype.h>
#include <limits.h>
#include <cstdlib>
#include <algorithm>
#include <vector>
#include <queue>
#include <map>
#include <stack>
#include <set>
#include <bitset>
#define CLR(a) memset(a, 0, sizeof(a))
#define REP(i, a, b) for(ll i = a;i < b;i++)
#define REP_D(i, a, b) for(ll i = a;i <= b;i++)
typedef long long ll;
using namespace std;
const ll maxn = 300 +10;
ll dp[maxn][maxn], n, tot, l, r;//好像用ll把。。。
ll ans;
void getDp()
{
tot = 300;
memset(dp, 0, sizeof(dp));
dp[0][0] = 1;//初始化,有一种方法
for(ll i = 1; i <= tot; i++)//完全背包
{
for(ll m = i; m <= tot; m++)//完全背包
{
for(ll k = 1; k <= tot; k++)
{
dp[m][k] = (dp[m][k]+dp[m-i][k-1]);//转移
}
}
}
}
void solve()
{
getDp();
char ch;
while(scanf("%lld%c", &tot, &ch) != EOF)
{
if(ch == '\n')
{
l = 0;
r = 300;
ans = 0;
for(ll i = l; i <= r; i++)
{
ans += dp[tot][i];
}
}
else
{
scanf("%lld%c", &l, &ch);
if(ch == '\n')
{
r = min(300ll, l);
l = 0;
ans = 0;
for(ll i = l; i <= r; i++)
{
ans += dp[tot][i];
}
}
else
{
scanf("%lld", &r);
l = min(300ll, l);
r = min(300ll, r);
ans = 0;
for(ll i = l; i <= r; i++)
{
ans += dp[tot][i];
}
}
}
printf("%lld\n", ans);
}
}
int main()
{
//freopen("4Din.txt", "r", stdin);
//freopen("4Dout.txt", "w", stdout);
solve();
return 0;
}