题意

题目链接

Sol

首先不难想到一种暴力dp,设\(f[i][a][b][c]\)表示还有\(i\)轮没打,场上有\(a\)个1血,\(b\)个2血,\(c\)个三血

发现状态数只有\(s = 166\)个,复杂度为\(O(ns)\)

矩乘优化一下复杂度为\(O(s^3 logn T)\),还是过不去。

因为每次询问都是独立的,那么可以预处理出\(2^i\)的转移矩阵,回答询问只需要拿一个行向量去乘log个矩阵

构造矩阵的时候可以加一个列向量表示期望

  1. #include<bits/stdc++.h>
  2. #define LL long long
  3. using namespace std;
  4. const int B = 60, mod = 998244353;
  5. template <typename A, typename B> inline bool chmin(A &a, B b){if(a > b) {a = b; return 1;} return 0;}
  6. template <typename A, typename B> inline bool chmax(A &a, B b){if(a < b) {a = b; return 1;} return 0;}
  7. template <typename A, typename B> inline LL add(A x, B y) {if(x + y < 0) return x + y + mod; return x + y >= mod ? x + y - mod : x + y;}
  8. template <typename A, typename B> inline void add2(A &x, B y) {if(x + y < 0) x = x + y + mod; else x = (x + y >= mod ? x + y - mod : x + y);}
  9. LL mul(int x, int y) {return 1ll * x * y % mod;}
  10. inline LL read() {
  11. char c = getchar(); LL x = 0, f = 1;
  12. while(c < '0' || c > '9') {if(c == '-') f = -1; c = getchar();}
  13. while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
  14. return x * f;
  15. }
  16. int fp(int a, int p) {
  17. int base = 1;
  18. while(p) {
  19. if(p & 1) base = mul(base, a);
  20. a = mul(a, a); p >>= 1;
  21. }
  22. return base;
  23. }
  24. int T, M, K;
  25. namespace S3 {
  26. int id[11][11][11], cnt, Lim;
  27. int ans[168];
  28. LL inv[11];
  29. struct Ma {
  30. int m[168][168];
  31. Ma() {
  32. memset(m, 0, sizeof(m));
  33. }
  34. void init() {
  35. for(int i = 0; i <= Lim; i++) m[i][i] = 1;
  36. }
  37. void print() {
  38. for(int i = 1; i <= Lim; i++, puts(""))
  39. for(int j = 1; j <= Lim; j++)
  40. printf("%d ", m[i][j]);
  41. }
  42. Ma operator * (const Ma &rhs) const {
  43. Ma gg = {};
  44. for(int i = 1; i <= Lim; i++)
  45. for(int j = 1; j <= Lim; j++) {
  46. __int128 tmp = 0;
  47. for(int k = 1; k <= Lim; k++)
  48. tmp += mul(m[i][k], rhs.m[k][j]);
  49. tmp %= mod;
  50. gg.m[i][j] = tmp;
  51. }
  52. return gg;
  53. }
  54. }f[B + 1];
  55. void Pre() {
  56. for(int i = 1; i <= K + 1; i++) inv[i] = fp(i, mod - 2);
  57. for(int a = 0; a <= K; a++)
  58. for(int b = 0; a + b <= K; b++)
  59. for(int c = 0; a + b + c <= K; c++)
  60. id[a][b][c] = ++cnt;
  61. for(int a = 0; a <= K; a++)
  62. for(int b = 0; a + b <= K; b++)
  63. for(int c = 0; a + b + c <= K; c++) {
  64. int down = inv[a + b + c + 1], tag = (a + b + c < K), now = id[a][b][c];
  65. if(a) f[0].m[now][id[a - 1][b][c]] = mul(a, down);
  66. if(b) f[0].m[now][id[a + 1][b - 1][c + tag]] = mul(b, down);
  67. if(c) f[0].m[now][id[a][b + 1][c - 1 + tag]] = mul(c, down);
  68. f[0].m[now][now] = down;
  69. f[0].m[now][cnt + 1] = down;
  70. }
  71. f[0].m[cnt + 1][cnt + 1] = 1;
  72. Lim = cnt + 1;
  73. for(int i = 1; i <= B; i++) f[i] = f[i - 1] * f[i - 1];
  74. }
  75. int tmp[168];
  76. void mul(Ma a) {
  77. memset(tmp, 0, sizeof(tmp));
  78. for(int j = 1; j <= Lim; j++)
  79. for(int i = 1; i <= Lim; i++)
  80. add2(tmp[j], 1ll * ans[i] * a.m[i][j] % mod);
  81. memcpy(ans, tmp, sizeof(tmp));
  82. }
  83. void MatrixPow(LL p) {
  84. for(int i = 0; p; p >>= 1, i++)
  85. if(p & 1)
  86. mul(f[i]);
  87. }
  88. void work() {
  89. Pre();
  90. while(T--) {
  91. LL n = read();
  92. memset(ans, 0, sizeof(ans)); ans[id[0][0][1]] = 1;
  93. MatrixPow(n);
  94. cout << ans[cnt + 1] << '\n';
  95. }
  96. }
  97. }
  98. namespace S2 {
  99. int id[11][11], cnt, Lim;
  100. int ans[168];
  101. LL inv[11];
  102. struct Ma {
  103. int m[168][168];
  104. Ma() {
  105. memset(m, 0, sizeof(m));
  106. }
  107. void init() {
  108. for(int i = 0; i <= Lim; i++) m[i][i] = 1;
  109. }
  110. void print() {
  111. for(int i = 1; i <= Lim; i++, puts(""))
  112. for(int j = 1; j <= Lim; j++)
  113. printf("%d ", m[i][j]);
  114. }
  115. Ma operator * (const Ma &rhs) const {
  116. Ma gg = {};
  117. for(int i = 1; i <= Lim; i++)
  118. for(int j = 1; j <= Lim; j++) {
  119. __int128 tmp = 0;
  120. for(int k = 1; k <= Lim; k++)
  121. tmp += mul(m[i][k], rhs.m[k][j]);
  122. tmp %= mod;
  123. gg.m[i][j] = tmp;
  124. }
  125. return gg;
  126. }
  127. }f[B + 1];
  128. void Pre() {
  129. for(int i = 1; i <= K + 1; i++) inv[i] = fp(i, mod - 2);
  130. for(int a = 0; a <= K; a++)
  131. for(int b = 0; a + b <= K; b++)
  132. id[a][b] = ++cnt;
  133. for(int a = 0; a <= K; a++)
  134. for(int b = 0; a + b <= K; b++) {
  135. int down = inv[a + b + 1], tag = (a + b < K), now = id[a][b];
  136. if(a) f[0].m[now][id[a - 1][b]] = mul(a, down);
  137. if(b) f[0].m[now][id[a + 1][b - 1 + tag]] = mul(b, down);
  138. f[0].m[now][now] = down;
  139. f[0].m[now][cnt + 1] = down;
  140. }
  141. f[0].m[cnt + 1][cnt + 1] = 1;
  142. Lim = cnt + 1;
  143. for(int i = 1; i <= B; i++) f[i] = f[i - 1] * f[i - 1];
  144. }
  145. int tmp[168];
  146. void mul(Ma a) {
  147. memset(tmp, 0, sizeof(tmp));
  148. for(int j = 1; j <= Lim; j++)
  149. for(int i = 1; i <= Lim; i++)
  150. add2(tmp[j], 1ll * ans[i] * a.m[i][j] % mod);
  151. memcpy(ans, tmp, sizeof(tmp));
  152. }
  153. void MatrixPow(LL p) {
  154. for(int i = 0; p; p >>= 1, i++)
  155. if(p & 1)
  156. mul(f[i]);
  157. }
  158. void work() {
  159. Pre();
  160. while(T--) {
  161. LL n = read();
  162. memset(ans, 0, sizeof(ans)); ans[id[0][1]] = 1;
  163. MatrixPow(n);
  164. cout << ans[cnt + 1] << '\n';
  165. }
  166. }
  167. }
  168. namespace S1 {
  169. int N, f[12][9][9][9];
  170. int inv(int a) {
  171. return fp(a, mod - 2);
  172. }
  173. void work() {
  174. N = 11;
  175. for(int i = 1; i <= N; i++) {
  176. for(int a = 0; a <= K; a++) {
  177. for(int b = 0; a + b <= K; b++) {
  178. for(int c = 0; a + b + c <= K; c++) {
  179. int down = a + b + c + 1;
  180. if(a) add2(f[i][a][b][c], mul(mul(a, inv(down)), f[i - 1][a - 1][b][c]));
  181. if(b) {
  182. if(down <= K) add2(f[i][a][b][c], mul(mul(b, inv(down)), f[i - 1][a + 1][b - 1 + (M == 2)][c + (M == 3)]));
  183. else add2(f[i][a][b][c], mul(mul(b, inv(down)), f[i - 1][a + 1][b - 1][c]));
  184. }
  185. if(c) {
  186. if(down <= K) add2(f[i][a][b][c], mul(mul(c, inv(down)), f[i - 1][a][b + 1 + (M == 2)][c - 1 + (M == 3)]));
  187. else add2(f[i][a][b][c], mul(mul(c, inv(down)), f[i - 1][a][b + 1][c - 1]));
  188. }
  189. add2(f[i][a][b][c], mul(inv(down), f[i - 1][a][b][c] + 1));
  190. }
  191. }
  192. }
  193. }
  194. while(T--) {
  195. int n = read();
  196. printf("%d\n", f[n][M == 1][M == 2][M == 3]);
  197. }
  198. }
  199. }
  200. int main() {
  201. T = read(); M = read(); K = read();
  202. if(M == 1) S1::work();
  203. else if(M == 2) S2::work();
  204. else S3::work();
  205. return 0;
  206. }

洛谷P4007 小 Y 和恐怖的奴隶主(期望dp 矩阵乘法)的更多相关文章

  1. 【loj2325】「清华集训 2017」小Y和恐怖的奴隶主 概率dp+倍增+矩阵乘法

    题目描述 你有一个m点生命值的奴隶主,奴隶主受伤未死且当前随从数目不超过k则再召唤一个m点生命值的奴隶主. T次询问,每次询问如果如果对面下出一个n点攻击力的克苏恩,你的英雄期望会受到到多少伤害. 输 ...

  2. 【UOJ#340】【清华集训2017】小 Y 和恐怖的奴隶主(矩阵快速幂,动态规划)

    [UOJ#340][清华集训2017]小 Y 和恐怖的奴隶主(矩阵快速幂,动态规划) 题面 UOJ 洛谷 题解 考虑如何暴力\(dp\). 设\(f[i][a][b][c]\)表示当前到了第\(i\) ...

  3. loj #2325. 「清华集训 2017」小Y和恐怖的奴隶主

    #2325. 「清华集训 2017」小Y和恐怖的奴隶主 内存限制:256 MiB时间限制:2000 ms标准输入输出 题目类型:传统评测方式:文本比较   题目描述 "A fight? Co ...

  4. 洛谷P3830 随机树(SHOI2012)概率期望DP

    题意:中文题,按照题目要求的二叉树生成方式,问(1)叶平均深度 (2)树平均深度 解法:这道题看完题之后完全没头绪,无奈看题解果然不是我能想到的qwq.题解参考https://blog.csdn.ne ...

  5. 洛谷P1291 [SHOI2002]百事世界杯之旅——期望DP

    题目:https://www.luogu.org/problemnew/show/P1291 水水的经典期望DP: 输出有毒.(其实也很简单啦) 代码如下: #include<iostream& ...

  6. 洛谷P1373 小a和uim之大逃离 dp

    正解:dp 解题报告: 传送门! 同样是看到列表发的题解就想着跟着做下dp的题目趴 然后发现还挺难的,,,反正我只大概想到怎么转移但是初始化什么的都不会TT 所以还是大概说下QAQ 首先可以想到设f[ ...

  7. [清华集训]小 Y 和恐怖的奴隶主

    题面在这里 题意 有一个\(Boss\)和他血量为\(m\)的随从奴隶主,每当奴隶主受到攻击且不死,并且\(Boss\)的随从个数\(<k\)时,就会新召唤一个血量为\(m\)的奴隶主.每次攻击 ...

  8. uoj#340. 【清华集训2017】小 Y 和恐怖的奴隶主(矩阵加速)

    传送门 uoj上的数据太毒了--也可能是我人傻常数大的缘故-- 三种血量的奴隶主加起来不超过\(8\)个,可以枚举每种血量的奴隶主个数,那么总的状态数只有\(165\)种,设\(dp_{t,i,j,k ...

  9. LibreOJ #2325. 「清华集训 2017」小Y和恐怖的奴隶主(矩阵快速幂优化DP)

    哇这题剧毒,卡了好久常数才过T_T 设$f(i,s)$为到第$i$轮攻击,怪物状态为$s$时对boss的期望伤害,$sum$为状态$s$所表示的怪物个数,得到朴素的DP方程$f(i,s)=\sum \ ...

随机推荐

  1. oracle对sum出来的数字进行非空补0处理

    oracle在使用函数计算式会遇到这样的情况:例如sum函数 如果计算的sum值为null,则用0替代 方法1(便于理解): select when sum(c.num) is null then   ...

  2. centos6.2升级到centos6.8(6.5应该也一样)

    1.根据这篇文章https://wenku.baidu.com/view/55bf7f8db8f67c1cfad6b8bf.html修改CentOS-Base.repo文件(主要是修改baseurl为 ...

  3. 机器学习基石笔记:12 Nonlinear Transformation

    一.二次假设 实际上线性假设的模型复杂度是受到限制的, 需要高次假设打破这个限制. 假设数据不是线性可分的,但是可以被一个圆心在原点的圆分开, 需要我们重新设计基于该圆的PLA等算法吗? 不用, 只需 ...

  4. spring boot 集成 Listener 的两种方式

    1)@ServletComponentScan注解+@WebListener注解 2)@Bean注解+ServletListenerRegistrationBean类

  5. Java language

    1.Java开发环境: java编译运行过程: 1. 编译期:.java源文件,经过编译,生成.class字节码文件 2. 运行期:JVM加载.class并运行.class - 特点:跨平台.一次编程 ...

  6. python 中range函数的用法

    一. range(start,end,step) 二.代码 [code1] for i in range(1,10,2): print("i=",i) [result1] i= 1 ...

  7. 高手速成android开源项目【View篇】

    主要介绍那些不错个性化的View,包括ListView.ActionBar.Menu.ViewPager.Gallery.GridView.ImageView.ProgressBar及其他如Dialo ...

  8. C#开发必会

    1.字符串的各种属性和方法: 2.数组的各种熟悉和方法: 3.public.private.protect.internal.protect internal 4.构造函数 5.属性 6.ADO.NE ...

  9. Shell脚本 | 性能测试之内存

    性能测试中,内存是一个不可或缺的方面.比如说在跑 Monkey 的过程中,如何准确持续的获取到内存数据就显得尤为重要. 今天分享一个脚本,可以在给定时间内持续监控内存,最后输出成一份 CSV 文件,通 ...

  10. 第4章 Selenium2-java WebDriver API (二)

    4.8  定位一组元素 定位一组元素的方法与定位单个元素的方法类似,唯一的区别是在单词element后面多了一个s表示复数.定位一组元素一般用于以下场景: ·批量操作元素,例如勾选页面上所有的复选框. ...