P6394
樱花,还有你
题目描述
与题意有关的句子已加粗。
但别急,我们就这样彳亍而行吧,需不着停留或回头,前面不是还有 \(k\) 棵樱花树么?我算了算,你可要收集恰好 \(n\) 朵樱花。我还发现,在第 \(i\) 棵树下最多能收集到 \(s_i\) 朵樱花(收集了 \(0\) 朵樱花也算收集了樱花)。
呐,考考你吧!你有多少种方案能够收集到恰好 \(n\) 朵樱花呢?
特殊地,如果你收集不到 \(n\) 朵樱花,请告诉我 impossible。
注意:如果你早早地收集到了 \(n\) 朵樱花,你可以立刻告诉我,也可以陪我继续向前走,一直到第 \(k\) 棵樱花树下收集了樱花后就必须交差啦!期间你在任何一棵树收集完樱花后就告诉我,形成的方案都是不同的哦!
输入格式
第一行两个正整数 \(n,k\),表示要收集 \(n\) 朵樱花,而前方还有 \(k\) 棵樱花树。
接下来一行 \(k\) 个正整数 \(s_1,s_2,\cdots,s_k\),其中 \(s_i\) 表示最多在第 \(i\) 棵樱花树下收集到 \(s_i\) 朵樱花。
输出格式
一行一个整数,表示恰好收集到 \(n\) 朵樱花的方案数。
由于答案可能太大,请输出答案对 \(10086001\) 取模后的值。
特殊地,如果收集不到 \(n\) 朵樱花,请输出一个字符串 impossible。
样例 #1
样例输入 #1
3 4
1 1 1 1
样例输出 #1
5
样例 #2
样例输入 #2
10 9
9 6 8 7 9 6 5 4 3
样例输出 #2
68345
样例 #3
样例输入 #3
10 5
2 2 2 2 1
样例输出 #3
impossible
提示
样例解释 #1
我们以下列方式表示一种方案:\((a_1,a_2,\cdots,a_{len})\),其中 \(\sum_{i=1}^{len} a_i =n\),\(len\) 表示在第 \(len\) 棵樱花树下收集完樱花后就交差了,\(a_i\) 表示在第 \(i\) 棵树下收集了 \(a_i\) 朵樱花。
那么有下列 \(5\) 种方案:\((1,1,1)\),\((1,1,1,0)\),\((0,1,1,1)\),\((1,0,1,1)\),\((1,1,0,1)\)。
样例解释 #3
最多能收集到 \(9\) 朵樱花,所以不能收集到 \(10\) 朵樱花,输出 impossible。
数据范围
本题采用捆绑测试。
- Subtask 1(5 Points),\(\sum s_i < n\)。
- Subtask 2(20 Points),\(n,k \leq 20\)。
- Subtask 3(55 Points),\(n,k \leq 5\times 10^2\)。
- Subtask 4(20 Points),\(n,k \leq 5\times 10^3\)。
对于 \(100\%\) 的数据,\(1 \leq n,k \leq 5\times 10^3\),\(0 \leq s_i \leq n\)。
多重背包+前缀和优化
点击查看代码
#include<iostream>
#include<cstdio>
using namespace std;
const int M=10086001;
int f[5001];
long long s[5001];//前缀和
int num,ans;
int main()
{
int n,t,i,j,p,k;
cin>>n>>k;
s[0]=f[0]=1;
for(i=1;i<=k;i++)
{
cin>>t;
for(j=1;j<=n;j++)//更新前缀和
s[j]=s[j-1]+f[j];
for(p=n;p>=0;p--)//多重背包
f[p]=(f[p]+s[p-1]-s[p-min(t,p)-1])%M;//利用前缀和
num+=t;//判断是否有解
ans=(ans+f[n])%M;//累加第i棵树下收集n朵花的方案
}
if(num<n)
cout<<"impossible";
else
cout<<ans;
return 0;
}

浙公网安备 33010602011771号