本文将同步发布于:

题目

题目描述

小 R 最近在玩一款游戏。在游戏中,小 R 要依次打 \(n\) 个怪兽,他需要打败至少 \(k\) 个怪兽才能通关。小 R 有两个属性值,分别是攻击力 \(A\) 和耐力 \(R\),每个怪兽也有两个属性值,分别是防御力 \(D\) 和生命值 \(H\)(不同的怪兽属性值可能不同)。小 R 每攻击一次怪兽,可以让怪兽的生命值减少 \(\max(A-D,1)\)点,同时小 R 的耐力会减少 \(1\)。怪兽不会攻击。若在一次攻击之后,怪兽的生命值 \(\leq 0\),则小 R 胜利。若在一次攻击之后,在怪兽的生命值大于 \(0\) 的条件下,小 \(R\) 的耐力值降低到了 \(0\),则怪兽胜利。在和一个怪兽战斗结束后,无论输赢,小 R 都会恢复全部的耐力值。

现在,小 R 的攻击 \(A\) 和每个怪兽的防御力 \(D\) 是确定的,小 R 的耐力值 \(R\) 是一个在 \([1,m]\) 区间内的整数,第 \(i\) 个怪兽的生命值是一个在 \([X_i,Y_i]\) 区间内的整数。求有多少种情况使得小 R 能通关,你只需要输出答案模 \(10^9+7\) 的值就可以了。

两种情况不同当且仅当这两种情况下小 R 的耐力值不同或者其中一个怪兽的生命值不同。

\(1\leq k\leq n\leq 50\),\(1\leq m,A,D_i\leq 10^9\)。

题解

简单暴力

考虑枚举耐力值 \(R\in [1,m]\),那么我们可以轻松得到一个关于方案数的动态规划:

即 \(d_i=\max(A-D_i,1)\)。

设 \(f_{i,j}\) 表示考虑前 \(i\) 个怪兽,打败恰好 \(j\) 个的方案数,我们不难得到转移。

\[\begin{cases}
f_{i-1,j-1}(Y_i-X_i+1)&\to f_{i,j},Rd_i\geq Y_i\\
f_{i-1,j}(Y_i-X_i+1)&\to f_{i,j},Rd_i<X_i\\
f_{i-1,j-1}(Rd_i-X_i+1)&\to f_{i,j},X_i\leq Rd_i<Y_i\\
f_{i-1,j}(Y_i-Rd_i)&\to f_{i,j},X_i\leq Rd_i<Y_i\\
\end{cases}
\]

这个算法的时间复杂度为 \(\Theta(n^2m)\)。

多项式

我们把 \(f_i\) 看作一个多项式,\(f_{i,j}\) 为 \(x^j\) 的系数。

那么上面的转移方程可以看作 \(f_i=f_{i-1}\times (ax+b)\)。

最后的结果就是对 \(x^k,x^{k+1},\cdots,x^n\) 的系数求和。

拉格朗日插值

考虑到上述式子可以表示为一个关于 \(R\) 的 \(n\) 次多项式,那么我们不妨用拉格朗日插值求出 \(n+2\) 个点值,求出前缀和的多项式表示,然后做差求解。

求出这个函数的分段点,插值即可。

参考程序

#pragma GCC optimize("Ofast")
#include<bits/stdc++.h>
using namespace std;
#define reg register
typedef long long ll;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
static char buf[1<<21],*p1=buf,*p2=buf;
inline int read(void){
reg char ch=getchar();
reg int res=0;
while(!isdigit(ch)) ch=getchar();
while(isdigit(ch)) res=10*res+(ch^'0'),ch=getchar();
return res;
} inline int max(reg int a,reg int b){
return a>b?a:b;
} inline int min(reg int a,reg int b){
return a<b?a:b;
} const int MAXN=50+5;
const int mod=1e9+7; struct modInt{
int x;
inline modInt(reg int x=0):x(x){
x=(x%mod+mod)%mod;
assert(0<=x&&x<mod);
return;
}
inline modInt operator+(const modInt& a)const{
reg int sum=x+a.x;
return sum>=mod?sum-mod:sum;
}
inline modInt operator-(const modInt& a)const{
reg int sum=x-a.x;
return sum<0?sum+mod:sum;
}
inline modInt operator*(const modInt& a)const{
return 1ll*x*a.x%mod;
}
inline void operator+=(const modInt& a){
x+=a.x;
if(x>=mod) x-=mod;
return;
}
inline void operator-=(const modInt& a){
x-=a.x;
if(x<0) x+=mod;
return;
}
inline void operator*=(const modInt& a){
x=1ll*x*a.x%mod;
return;
}
}; inline modInt fpow(modInt x,reg int exp){
modInt res=1;
while(exp){
if(exp&1)
res*=x;
x*=x,exp>>=1;
}
return res;
} inline modInt operator/(const modInt& a,const modInt& b){
return a*fpow(b,mod-2);
} inline void operator/=(modInt& a,const modInt& b){
a*=fpow(b,mod-2);
return;
} struct Node{
int delta,l,r;
}; int n,m,k,A;
Node a[MAXN];
modInt f[MAXN][MAXN]; inline modInt getVal(reg int R){
for(reg int i=0;i<=n;++i)
for(reg int j=0;j<=i;++j)
f[i][j]=0;
f[0][0]=1;
for(reg int i=0;i<n;++i){
for(reg int j=0;j<=i;++j)
if(f[i][j].x){
reg ll val=1ll*a[i+1].delta*R;
if(val>=a[i+1].r)
f[i+1][j+1]+=f[i][j]*(a[i+1].r-a[i+1].l+1);
//(len) x
else if(val<a[i+1].l)
f[i+1][j]+=f[i][j]*(a[i+1].r-a[i+1].l+1);
//(len)
else{
f[i+1][j]+=f[i][j]*(a[i+1].r-val);
f[i+1][j+1]+=f[i][j]*(val-a[i+1].l+1);
//(rig)+(lef)*x
}
}
}
modInt res=0;
for(reg int i=k;i<=n;++i)
res+=f[n][i];
return res;
} int B; inline modInt Lagrange(reg int lef,reg int rig,modInt x[],modInt y[],reg int X){
modInt res=0;
for(reg int i=lef;i<=rig;++i){
modInt pod=1;
for(reg int j=lef;j<=rig;++j)
if(i!=j)
pod*=(modInt(X)-x[j])/(x[i]-x[j]);
res+=y[i]*pod;
}
return res;
} inline modInt getAns(reg int lef,reg int rig){
if(rig-lef+1<=B){
modInt res=0;
for(reg int i=lef;i<=rig;++i)
res+=getVal(i);
return res;
}
else{
modInt x[B],y[B];
for(reg int i=0;i<B;++i)
x[i]=lef+i,y[i]=getVal(lef+i);
for(reg int i=1;i<B;++i)
y[i]+=y[i-1];
return Lagrange(0,B-1,x,y,rig)-Lagrange(0,B-1,x,y,lef-1);
}
} int main(void){
n=read(),m=read(),k=read(),A=read();
B=n+2;
for(reg int i=1;i<=n;++i){
static int d,x,y;
d=read(),x=read(),y=read();
a[i].delta=max(A-d,1),a[i].l=x,a[i].r=y;
}
vector<int> V;
V.push_back(1),V.push_back(m+1);
for(reg int i=1;i<=n;++i){
V.push_back((a[i].l+a[i].delta-1)/a[i].delta);
V.push_back(a[i].r/a[i].delta+1);
}
sort(V.begin(),V.end()),V.erase(unique(V.begin(),V.end()),V.end());
while(V.back()>m+1) V.pop_back();
modInt ans=0;
for(reg int i=1,siz=V.size();i<siz;++i)
ans+=getAns(V[i-1],V[i]-1);
printf("%d\n",ans.x);
return 0;
}

「题解」小 R 打怪兽 monster的更多相关文章

  1. 「NOI2013」小 Q 的修炼 解题报告

    「NOI2013」小 Q 的修炼 第一次完整的做出一个提答,花了半个晚上+一个上午+半个下午 总体来说太慢了 对于此题,我认为的难点是观察数据并猜测性质和读入操作 我隔一会就思考这个sb字符串读起来怎 ...

  2. 「SCOI2015」小凸想跑步 解题报告

    「SCOI2015」小凸想跑步 最开始以为和多边形的重心有关,后来发现多边形的重心没啥好玩的性质 实际上你把面积小于的不等式列出来,发现是一次的,那么就可以半平面交了 Code: #include & ...

  3. 「SCOI2015」小凸解密码 解题报告

    「SCOI2015」小凸解密码 题意:给一个环,定义一段连续的极长\(0\)串为\(0\)区间,定义一个位置的离一个\(0\)区间的距离为这个位置离这个区间中\(0\)的距离的最小值,每次询问一个位置 ...

  4. 「SCOI2015」小凸玩矩阵 解题报告

    「SCOI2015」小凸玩矩阵 我好沙茶啊 把点当边连接行和列,在外面二分答案跑图的匹配就行了 我最开始二分方向搞反了,样例没过. 脑袋一抽,这绝壁要费用流,连忙打了个KM 然后wa了,一想这个不是完 ...

  5. loj#2009.「SCOI2015」小凸玩密室

    题目链接 loj#2009. 「SCOI2015」小凸玩密室 题解 树高不会很高<=20 点亮灯泡x,点亮x的一个子树,再点亮x另外的子树, 然后回到x的父节点,点亮父节点之后再点亮父节点的其他 ...

  6. LibreOJ #2006. 「SCOI2015」小凸玩矩阵 二分答案+二分匹配

    #2006. 「SCOI2015」小凸玩矩阵 内存限制:256 MiB时间限制:1000 ms标准输入输出 题目类型:传统评测方式:文本比较 上传者: 匿名 提交提交记录统计讨论测试数据   题目描述 ...

  7. AC日记——「SCOI2015」小凸玩矩阵 LiBreOJ 2006

    「SCOI2015」小凸玩矩阵 思路: 二分+最大流: 代码: #include <bits/stdc++.h> using namespace std; #define maxn 300 ...

  8. loj #2008. 「SCOI2015」小凸想跑步

    #2008. 「SCOI2015」小凸想跑步   题目描述 小凸晚上喜欢到操场跑步,今天他跑完两圈之后,他玩起了这样一个游戏. 操场是个凸 n nn 边形,N NN 个顶点按照逆时针从 0∼n−1 0 ...

  9. loj #2006. 「SCOI2015」小凸玩矩阵

    #2006. 「SCOI2015」小凸玩矩阵   题目描述 小凸和小方是好朋友,小方给小凸一个 N×M N \times MN×M(N≤M N \leq MN≤M)的矩阵 A AA,要求小凸从其中选出 ...

随机推荐

  1. Python练习1-文档格式化成html

    文档格式化成HTML 把文档格式化成了THML,并没有处理所有thml规则,只是处理了一部分,功能不重要,重要的是复习熟悉下Python对文档的处理细节.毕竟Python大多数给我的印象都是处理文档. ...

  2. 制作 PPT 的新方式出现了——GitHub 热点速览 v.21.19

    作者:HelloGitHub-小鱼干 想当初 Markdown 的出现,拯救了多少死在 Word 样式调整上的人,现在,slidev 出现了,它让你 Focus 在本该专注的 PPT 内容制作上而不需 ...

  3. Instagram 为什么不用redis

    Hi 我还是大粽子 碎碎念 让我比较兴奋的就是这段时间的文章,被感兴趣的同学一一关注,关注量上涨就是我的最大动力. 我每周都会输出至少3篇原创文章,希望能被更多的同学关注,点赞,在看,形成习惯. In ...

  4. 程序时间计算函数(被tle出阴影来了)

    初次意识到程序的时间复杂度(tle多了 ) 第一次写博客(被大佬们的博客所折服orz) 拿打素数表的程序为例 优化前代码: #include<iostream> #include<c ...

  5. [bug] Flask:jinja2.exceptions.UndefinedError: 'None' has no attribute 'id'

    问题 Python Flask做的购物网站,添加购物车时,提示错误 解决 检查发现是MySQL中不正常的空数据导致,删除此条记录即可 参考 https://www.jb51.cc/python/186 ...

  6. [bug] Importing maven project 卡在%9不动

    参考 Importing maven project 卡在%9不动 https://blog.csdn.net/weixin_43197380/article/details/89220337

  7. 【山外笔记-工具框架】SVN版本控制系统

    [山外笔记-框架工具]SVN版本控制系统 学习资料: 1.本文打印版下载地址:[山外笔记-框架工具笔记]SVN版本控制工具-打印版.pdf 2.SVN和TortoiseSVN在线中文文档:http:/ ...

  8. 1.5 RPM红帽软件包1.6 Yum软件仓库

    1.5 RPM红帽软件包 在RPM(红帽软件包管理器)公布之前,要想在Linux系统中安装软件只能采取源码包的方式安装.早期在Linux系统中安装程序是一件非常困难.耗费耐心的事情,而且大多数的服务程 ...

  9. linux patch中的p0和p1的区别

    命令patch的主要作用是生成diff文件和应用diff文件.举个例子来讲,当发现某个程序出现bug需要打补丁时,patch便是一个好工具. diff文件头: [root@localhost kern ...

  10. Keepalived+nginx高可用

    这种方法会把Keepalived进程结束掉,在教育机构学习到的方法,我个人对这种方法不认可. 参考: https://www.cnblogs.com/gshelldon/p/14504236.html ...