题目链接

首先dp很显然,\(f(i,s)\)表示到了第i轮,各种血量人数的情况为s今后的期望攻击boss次数。那么有\(f(i,s)=\frac{1}{num+1}*\sum_{s->s'}(f(i+1,s')+0/1)\),num为奴隶主个数,当攻击boss时后面的贡献就是1,否则是0,s可以用一个m位k+1进制数来表示(代表血量为1,2,3的奴隶主个数)。

然后处理出s的转移需要哪些状态(总状态数为\(tot=C_{10}^2+C_9^2+...+C_2^2=165\)),那么可以矩乘优化了。由于有多组询问,因此可以预处理出矩阵的\(2^k\)次方,但由于这样做询问时的复杂度还是\(O(tot^3logn)\)的,我们想到最边上的矩阵是\(tot*1\)的,且一个\(tot*tot\)的矩阵与\(tot*1\)的矩阵乘出来还是\(tot*1\)的,因此可以从\(tot*1\)的矩阵开始一路向左乘,这样复杂度就是\(O(tot^2logn)\)的。

总复杂度\(O(tot^3logn+T*tot^2logn)\),矩乘那里需要卡卡常。

  1. #include<cstdio>
  2. #include<cstdlib>
  3. #include<cstring>
  4. #include<iostream>
  5. #include<vector>
  6. #include<algorithm>
  7. #include<cmath>
  8. #define P puts("lala")
  9. #define cp cerr<<"lala"<<endl
  10. #define ln putchar('\n')
  11. #define pb push_back
  12. #define fi first
  13. #define se second
  14. #define mkp make_pair
  15. using namespace std;
  16. inline int read()
  17. {
  18. char ch=getchar();int g=1,re=0;
  19. while(ch<'0'||ch>'9') {if(ch=='-')g=-1;ch=getchar();}
  20. while(ch<='9'&&ch>='0') re=(re<<1)+(re<<3)+(ch^48),ch=getchar();
  21. return re*g;
  22. }
  23. typedef long long ll;
  24. typedef pair<int,int> pii;
  25. const int N=201;
  26. const int mod=998244353;
  27. const ll MOD=(0x7fffffffffffffffll/mod-mod)*mod;
  28. const ll MAXN=1e18;
  29. const int maxb=59;
  30. ll qpow(ll a,int n)
  31. {
  32. ll ans=1;
  33. for(;n;n>>=1,a=a*a%mod) if(n&1) ans=ans*a%mod;
  34. return ans;
  35. }
  36. struct mat
  37. {
  38. int n,m;
  39. int s[169][169];
  40. mat() {clean();}
  41. void clean() {memset(s,0,sizeof(s));n=m=0;}
  42. };
  43. mat c;
  44. ll tmp[169][169];
  45. mat operator * (const mat &a,const mat &b)
  46. {
  47. c.n=a.n; c.m=b.m;
  48. for(int i=0;i<a.n;++i) for(int k=0;k<a.m;++k)
  49. {
  50. if(!a.s[i][k]) continue;
  51. for(int j=0;j<b.m;++j) if((tmp[i][j]+=1ll*a.s[i][k]*b.s[k][j])>=MOD)
  52. tmp[i][j]-=MOD;
  53. //c.s[i][j]=(c.s[i][j]+1ll*a.s[i][k]*b.s[k][j]%mod)%mod;
  54. }
  55. for(int i=0;i<c.n;++i) for(int j=0;j<c.m;++j)
  56. c.s[i][j]=tmp[i][j]%mod,tmp[i][j]=0;
  57. return c;
  58. }
  59. mat matpw[70],X,V;
  60. int id[N],is[N],tot=0,pw[15],K,m,k;
  61. ll n;
  62. void wj()
  63. {
  64. #ifndef ONLINE_JUDGE
  65. freopen("1.in","r",stdin);
  66. freopen("1.out","w",stdout);
  67. #endif
  68. }
  69. int main()
  70. {
  71. wj();
  72. int i,j,opt,T;
  73. T=read(); m=read(); k=read();
  74. K=k+1; pw[0]=1;
  75. for(i=1;i<=m;++i) pw[i]=pw[i-1]*K;
  76. for(i=0;i<pw[m];++i)
  77. {
  78. int s=0;
  79. for(j=0;j<m;++j) s+=i/pw[j]%K;
  80. if(s<=k) is[tot]=i,id[i]=tot,tot++;
  81. }
  82. X.n=tot+1; X.m=1;
  83. X.s[tot][0]=1;
  84. matpw[0].n=matpw[0].m=tot+1;
  85. matpw[0].s[tot][tot]=1;
  86. for(int idx=0;idx<tot;++idx)
  87. {
  88. int num=0;
  89. for(i=0;i<m;++i) num+=is[idx]/pw[i]%K;
  90. int inv=qpow(num+1,mod-2);
  91. matpw[0].s[idx][tot]=inv; matpw[0].s[idx][idx]=inv;
  92. int x=is[idx];
  93. for(i=0;i<m;++i) if(x/pw[i]%K)
  94. {
  95. x-=pw[i];
  96. if(i) x+=pw[i-1];
  97. if(i&&num<k) x+=pw[m-1];
  98. (matpw[0].s[idx][id[x]]+=1ll*inv*(is[idx]/pw[i]%K)%mod)%=mod;
  99. x=is[idx];
  100. }
  101. }
  102. for(i=1;i<=maxb;++i) matpw[i]=matpw[i-1]*matpw[i-1];
  103. int ans=pw[m-1];
  104. for(int cas=1;cas<=T;++cas)
  105. {
  106. scanf("%lld",&n);
  107. V=X;
  108. for(i=0;i<=maxb;++i) if(n&(1ll<<i)) V=matpw[i]*V;
  109. printf("%d\n",V.s[id[ans]][0]);
  110. }
  111. return 0;
  112. }

LOJ2325「清华集训 2017」小Y和恐怖的奴隶主的更多相关文章

  1. LOJ2325. 「清华集训 2017」小 Y 和恐怖的奴隶主【矩阵快速幂优化DP】【倍增优化】

    LINK 思路 首先是考虑怎么设计dp的状态 发现奴隶主的顺序没有影响,只有生命和个数有影响,所以就可以把每个生命值的奴隶主有多少压缩成状态就可以了 然后发现无论是什么时候一个状态到另一个状态的转移都 ...

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

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

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

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

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

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

  5. Loj #2324. 「清华集训 2017」小 Y 和二叉树

    Loj #2324. 「清华集训 2017」小 Y 和二叉树 小Y是一个心灵手巧的OIer,她有许多二叉树模型. 小Y的二叉树模型中,每个结点都具有一个编号,小Y把她最喜欢的一个二叉树模型挂在了墙上, ...

  6. [LOJ#2324]「清华集训 2017」小Y和二叉树

    [LOJ#2324]「清华集训 2017」小Y和二叉树 试题描述 小Y是一个心灵手巧的OIer,她有许多二叉树模型. 小Y的二叉树模型中,每个结点都具有一个编号,小Y把她最喜欢的一个二叉树模型挂在了墙 ...

  7. [LOJ#2323]「清华集训 2017」小Y和地铁

    [LOJ#2323]「清华集训 2017」小Y和地铁 试题描述 小Y是一个爱好旅行的OIer.一天,她来到了一个新的城市.由于不熟悉那里的交通系统,她选择了坐地铁. 她发现每条地铁线路可以看成平面上的 ...

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

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

  9. loj2324 「清华集训 2017」小 Y 和二叉树

    https://loj.ac/problem/2324 太智障,一开始以为中序遍历的第一个点一定是一个叶子,想了个贪心.然而,手算了一下,第一个点都过不了啊. input 5 2 3 4 1 3 3 ...

随机推荐

  1. C#爬虫之通过Selenium获取浏览器请求响应结果

    前言 在进行某些爬虫任务的时候,我们经常会遇到仅用Http协议难以攻破的情况,比如协议中带有加密参数,破解需要花费大量时间,那这时候就会用Selenium去模拟浏览器进行页面上的元素抓取 大多数情况下 ...

  2. linux-0.11分析:init文件 main.c的第一个初始化函数mem_int 第四篇随笔

    init文件夹 mian.c 参考 [github这个博主的 厉害][ https://github.com/sunym1993/flash-linux0.11-talk ] 首先先看看这个mian. ...

  3. 简单学习一下ibd数据文件解析

    来源:原创投稿 作者:花家舍 简介:数据库技术爱好者. GreatSQL社区原创内容未经授权不得随意使用,转载请联系小编并注明来源. 简单学习一下数据文件解析 这是尝试使用Golang语言简单解析My ...

  4. 一分钟安装DolphinScheduler并上手体验

    一分钟安装Apache DolphinScheduler并上手体验 1 一分钟安装DolphinScheduler并上手体验 本教程基于DolphinScheduler1.3.2 2 需要准备: 一台 ...

  5. mybatis 13: 一对多关联查询

    业务背景 根据客户id查询客户基本信息,以及客户存在的订单信息 两张数据表 客户表 订单表 实体类 客户实体类:Customer private Integer id; private String ...

  6. postgresql用户与权限管理

    pg使用角色的概念管理数据库访问权限,角色是一系列相关权限的集合.为了管理方便,通常把一系列先关的权限赋予给一个角色,如果哪个用户需要这些权限,就把这些角色赋予给响应的用户. 由于用户也拥有一系列的相 ...

  7. postgresql使用group by进行数据去重-2022新项目

    一.业务场景 数据去重是web开发中经常会遇到的方式之一,数据库操作中有一个关键字distinct主要就是用来做这件事,用来进行去重. 比如进行统计查询的时候,可以这样写 select count(d ...

  8. 从零开始实现一个MyBatis加解密插件

    作者:vivo 互联网服务器团队- Li Gang 本篇文章介绍使用MyBatis插件来实现数据库字段加解密的过程. 一.需求背景 公司出于安全合规的考虑,需要对明文存储在数据库中的部分字段进行加密, ...

  9. [2021.4.9多校省选模拟35]隐形斗篷 (prufer序列,背包DP)

    题面 我编不下去了! 给出 n n n 个点,第 i i i 个点的度数限制为 a i a_i ai​,现在需要选出 x x x 个点构成一颗树,要求这 x x x 个点中每个点的度数不超过这个点的 ...

  10. python使用pickle序列化对象读取输出二进制文件

    import pickle class tick: name = '牛牛牛' age = 10 samp = [1,2,3,'aaa',[12,3],tick()] with open('te.xxx ...