题目描述
九条可怜最近在玩一个大型无双游戏。 在游戏的数据库中,有 n 个敌人,每一个敌人有两个属性,血量 hi 和攻击力 ai。每一关游戏中,游戏会从数据库中随机选出若干个敌人(至少一个)来形成关卡。显然一共有 2n-1 种不同的游戏。 因为这时一个无双游戏,因此可怜有无限的血量和 imba 的攻击方式:当可怜每按一次攻击键,都会对所有敌人产生 1 点伤害(血量减一)。 当一个敌人在血量小于等于 0 的时候会发动自爆,它会对场上所有还存活的单位造成 ai 的伤害(同时死亡则同时自爆)。因为可怜的血量是无限的,所以自爆的唯一作用就是帮助可怜攻击场上还存活的敌人。 举例来说,如果有四个敌人,血量分别为 1,1,4,7,攻击力分别为 2,2,1,1。则可怜在攻击一次之后,会产生以下的连锁反应: 1. 敌人的血量降为 0,0,3,6,前两个敌人同时发动自爆。 2. 敌人的血量降为 0,0,-1,2,第三个敌人发动自爆。 3. 敌人的血量降为 0,0,-1,1,连锁反应结束。 我们可以假设敌人的自爆是在瞬间完成的,即可怜在按下攻击键之前,之前的所有攻击引发的自爆以及连锁反应都已经结束了。 显然不管游戏怎么样,只要可怜攻击足够多次,她都能消灭所有敌人。但是可怜是一个懒惰的女孩子,她想要知道在所有的 2n-1 种可能的游戏中,在 K 次攻击内就能消灭所有敌人的有多少种。
输入描述:
输入一行两个整数 n,K。第二行 n 个整数 hi 表示血量。第三行 n 个整数 ai 表示攻击力。对于 的数据,n ≤ 20。对于 的数据,n ≤ 100, hi,ai,K ≤ 1000。对于 的数据,1 ≤ n ≤ 1000, 1 ≤ hi,ai, K ≤ 105。
输出描述:
输出一行一个整数表示答案,答案可能很大,对 998244353 取模后输出。
示例1
输入
4 1
1 1 4 7
2 2 1 1
输出
4
思路
敌人肯定会按照血量顺序死亡的,所以把所有敌人按照血量升序排序
第 i 个敌人会受到 K+sum{j < i} a[j] 点伤害,这个敌人会死亡当只会在这个数值大于等于 h[i]
dp[i][j],表示当前考虑了前 i 个敌人,所有加入游戏的敌人的攻击力的和为j
代码
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+100;
const int mod=998244353;
struct node
{
int a,h;
}p[maxn];
int n,k,dp[maxn];
bool cmp(node x,node y)
{
return x.h<y.h;
}
int main()
{
scanf("%d%d",&n,&k);
for(int i=1;i<=n;i++)
scanf("%d",&p[i].h);
for(int i=1;i<=n;i++)
scanf("%d",&p[i].a);
sort(p+1,p+1+n,cmp);
dp[0]=1;
for(int i=1;i<=n;i++)
{
for(int j=100000;j>=0;j--)
{
if(j+k>=p[i].h)
{
int ans=min(100000,j+p[i].a);
dp[ans]+=dp[j];
dp[ans]%=mod;
}
}
}
int sum=0;
for(int i=1;i<=100000;i++)
{
sum+=dp[i];
sum%=mod;
}
printf("%d\n",sum);
return 0;
}
来源:nkw