loj2538 「PKUWC2018」Slay the Spire 【dp】
题目链接
题解
比较明显的是,由于强化牌倍数大于\(1\),肯定是能用强化牌尽量用强化牌
如果强化牌大于等于\(k\),就留一个位给攻击牌
所以我们将两种牌分别排序,企图计算\(F(i,j)\)表示\(i\)张强化牌选出最强的\(j\)张的所有方案的倍数和
\(G(i,j)\)表示从\(i\)张攻击牌选出最强\(j\)张的所有方案的伤害和
那么
\]
所以我们只需计算出\(F\)和\(G\)
以\(F\)为例,我们枚举选出最后一张牌是什么
那么设\(f[i][j]\)表示用了\(i\)张强化牌,最后一张是\(j\)的倍数和
同样设\(g[i][j]\)表示用了\(i\)张攻击牌,最后一张是\(j\)的伤害和
那么有
\]
\]
可用前缀和优化为\(O(n^2)\)
那么
\]
\]
总复杂度\(O(Tn^2)\)
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<map>
#define Redge(u) for (int k = h[u],to; k; k = ed[k].nxt)
#define REP(i,n) for (int i = 1; i <= (n); i++)
#define mp(a,b) make_pair<int,int>(a,b)
#define cls(s) memset(s,0,sizeof(s))
#define cp pair<int,int>
#define LL long long int
using namespace std;
const int maxn = 3005,maxm = 100005,INF = 1000000000,P = 998244353;
inline int read(){
int out = 0,flag = 1; char c = getchar();
while (c < 48 || c > 57){if (c == '-') flag = -1; c = getchar();}
while (c >= 48 && c <= 57){out = (out << 3) + (out << 1) + c - 48; c = getchar();}
return out * flag;
}
int n,m,K,fac[maxn],fv[maxn],inv[maxn];
int w1[maxn],w2[maxn];
int f[maxn][maxn],g[maxn][maxn];
int s[maxn];
void init(){
fac[0] = fac[1] = inv[0] = inv[1] = fv[0] = fv[1] = 1;
for (int i = 2; i <= 3000; i++){
fac[i] = 1ll * fac[i - 1] * i % P;
inv[i] = 1ll * (P - P / i) * inv[P % i] % P;
fv[i] = 1ll * fv[i - 1] * inv[i] % P;
}
}
inline int C(int n,int m){
if (n < m) return 0;
return 1ll * fac[n] * fv[m] % P * fv[n - m] % P;
}
inline int F(int x,int y){
if (x > n || x < y) return 0;
int re = 0;
for (int i = 0; i <= n; i++)
re = (re + 1ll * f[y][i] * C(n - i,x - y) % P) % P;
return re;
}
inline int G(int x,int y){
if (x > n || x < y) return 0;
int re = 0;
for (int i = 0; i <= n; i++)
re = (re + 1ll * g[y][i] * C(n - i,x - y) % P) % P;
return re;
}
inline bool cmp(const int& a,const int& b){
return a > b;
}
void work(){
sort(w1 + 1,w1 + 1 + n,cmp);
sort(w2 + 1,w2 + 1 + n,cmp);
for (int i = 0; i <= n; i++)
for (int j = 0; j <= n; j++)
f[i][j] = g[i][j] = 0;
f[0][0] = 1;
s[0] = 1;
for (int i = 1; i <= n; i++) s[i] = s[i - 1];
for (int i = 1; i <= n; i++){
for (int j = i; j <= n; j++){
f[i][j] = 1ll * w1[j] * s[j - 1] % P;
}
for (int j = 0; j < i; j++) s[j] = 0;
for (int j = i; j <= n; j++) s[j] = (s[j - 1] + f[i][j]) % P;
}
s[0] = 0;
for (int i = 1; i <= n; i++) s[i] = s[i - 1];
for (int i = 1; i <= n; i++){
for (int j = i; j <= n; j++){
g[i][j] = (1ll * w2[j] * C(j - 1,i - 1) % P + s[j - 1]) % P;
}
for (int j = 0; j < i; j++) s[j] = 0;
for (int j = i; j <= n; j++) s[j] = (s[j - 1] + g[i][j]) % P;
}
int ans = 0;
for (int i = 0; i <= min(n,m); i++){
int j = m - i; if (j < 0 || j > n) continue;
if (i < K){
ans = (ans + 1ll * F(i,i) * G(j,K - i) % P) % P;
}
else{
ans = (ans + 1ll * F(i,K - 1) * G(j,1) % P) % P;
}
}
printf("%d\n",ans);
}
int main(){
init();
int T = read();
while (T--){
n = read(); m = read(); K = read();
REP(i,n) w1[i] = read();
REP(i,n) w2[i] = read();
work();
}
return 0;
}
loj2538 「PKUWC2018」Slay the Spire 【dp】的更多相关文章
- LOJ2538. 「PKUWC2018」Slay the Spire【组合数学】
LINK 思路 首先因为式子后面把方案数乘上了 所以其实只用输出所有方案的攻击力总和 然后很显然可以用强化牌就尽量用 因为每次强化至少把下面的牌翻一倍,肯定是更优的 然后就只有两种情况 强化牌数量少于 ...
- loj #2538. 「PKUWC2018」Slay the Spire
$ \color{#0066ff}{ 题目描述 }$ 九条可怜在玩一个很好玩的策略游戏:Slay the Spire,一开始九条可怜的卡组里有 \(2n\) 张牌,每张牌上都写着一个数字\(w_i\) ...
- 【LOJ】#2538. 「PKUWC2018」Slay the Spire
题解 由于强化卡都是大于1的,我们分析一下就会发现,尽可能多的用强化卡,至少用一张攻击卡,一定是每组卡牌的最优选择 所以我们把攻击卡和强化卡从大到小排序 我们设\(g[i][j]\)表示前i张卡牌里选 ...
- 「PKUWC2018」Slay the Spire
题目链接 题意分析 这个题其实不是期望 就是一共有\(C_{2n}^m\)种情况 每一种情况选择\(k\)张牌 然后求最大攻击值的总和 我们考虑 当前抽出了选出了\(i\)张强化牌 \(m-i\)张攻 ...
- LOJ #2538. 「PKUWC 2018」Slay the Spire (期望dp)
Update on 1.5 学了 zhou888 的写法,真是又短又快. 并且空间是 \(O(n)\) 的,速度十分优秀. 题意 LOJ #2538. 「PKUWC 2018」Slay the Spi ...
- loj2542 「PKUWC2018」随机游走 【树形dp + 状压dp + 数学】
题目链接 loj2542 题解 设\(f[i][S]\)表示从\(i\)节点出发,走完\(S\)集合中的点的期望步数 记\(de[i]\)为\(i\)的度数,\(E\)为边集,我们很容易写出状态转移方 ...
- LOJ2542. 「PKUWC2018」随机游走【概率期望DP+Min-Max容斥(最值反演)】
题面 思路 我们可以把到每个点的期望步数算出来取max?但是直接算显然是不行的 那就可以用Min-Max来容斥一下 设\(g_{s}\)是从x到s中任意一个点的最小步数 设\(f_{s}\)是从x到s ...
- Loj #2542. 「PKUWC2018」随机游走
Loj #2542. 「PKUWC2018」随机游走 题目描述 给定一棵 \(n\) 个结点的树,你从点 \(x\) 出发,每次等概率随机选择一条与所在点相邻的边走过去. 有 \(Q\) 次询问,每次 ...
- 「PKUWC2018」随机游走(min-max容斥+FWT)
「PKUWC2018」随机游走(min-max容斥+FWT) 以后题目都换成这种「」形式啦,我觉得好看. 做过重返现世的应该看到就想到 \(min-max\) 容斥了吧. 没错,我是先学扩展形式再学特 ...
随机推荐
- GearCase UI - 自己构建一套基于 Vue 的简易开源组件库
最近 1 ~ 2 月除了开发小程序之外,还一直在继续深入的学习 Vuejs.利用零碎.闲暇的时间整合了一套基于 Vue 的 UI 组件库.命名为 GearCase UI,意为齿轮盒.现在把该项目进行开 ...
- Netty源码分析第6章(解码器)---->第4节: 分隔符解码器
Netty源码分析第六章: 解码器 第四节: 分隔符解码器 基于分隔符解码器DelimiterBasedFrameDecoder, 是按照指定分隔符进行解码的解码器, 通过分隔符, 可以将二进制流拆分 ...
- ats Linux Bridge内联
Linux可以配置为在桥接模式下运行. 为网桥分配了两个或更多物理接口. 在接口之间共享单个IP地址. 默认情况下,任何到达一个接口的数据包都会立即路由到另一个网桥接口. 需要的Linux包: bri ...
- 记一次nginx -t非常慢的排障经历
在一次修改nginx配置时候,执行 case: #/usr/local/nginx/sbin/nginx -t 出现执行命令出现很久没返回结果,也没返回成功或是失败,就是一直卡住的状态,严重影响ngi ...
- 如何通过阿里云APP进行域名备案?阿里云备案流程需要多久?
如何通过阿里云APP进行域名备案? 1.准备备案材料(很多初次使用阿里云APP进行备案的同学会问备案需要准备哪些资料,不二版本下面就给大家一一列举出来) 个人备案需要材料: ⑴<用户网站备案授权 ...
- React Native移动开发实战-5-Android平台的调试技巧
Android平台的调试和其他平台的调试也很类似,例如:在Android Studio打开的工程中,打开源码MainActivity.java,然后,将鼠标移至代码编辑区的左侧后,单击鼠标即可添加断点 ...
- which命令详解
基础命令学习目录首页 原文链接:https://www.cnblogs.com/jkin/p/10289085.html Linux which命令用于查找文件. which指令会在环境变量$PATH ...
- Daily Scrum6 11.10
今日任务: 徐钧鸿:codingcook的sql相关内容,并在进行复查张艺:继续用户管理部分代码黄可嵩:学习搜索的知识,继续进行搜索的移植和响应徐方宇:动态控件和页面间信息传递以及页面响应事件机制试验 ...
- Scrum Meeting 11.03
成员 今日任务 明日计划 用时 徐越 休息 赵庶宏 编写功能说明书,servlet代码移植 servlet代码移植 3h 薄霖 阅读上一届相关代码,思考改进方法 学习安卓界面设计数据库管理 4 ...
- Android笔记-2-TextView的属性详解
[Android 基础]TextView的属性详解 android:autoLink :设置是否当文本为URL链接/email/电话号码/map时,文本显示为可点击的链接.可选值(none/web / ...