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;
}
posted @ 2023-01-13 16:38  PKU_IMCOMING  阅读(10)  评论(0)    收藏  举报