题目链接

首先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)\),矩乘那里需要卡卡常。

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<vector>
#include<algorithm>
#include<cmath>
#define P puts("lala")
#define cp cerr<<"lala"<<endl
#define ln putchar('\n')
#define pb push_back
#define fi first
#define se second
#define mkp make_pair
using namespace std;
inline int read()
{
char ch=getchar();int g=1,re=0;
while(ch<'0'||ch>'9') {if(ch=='-')g=-1;ch=getchar();}
while(ch<='9'&&ch>='0') re=(re<<1)+(re<<3)+(ch^48),ch=getchar();
return re*g;
}
typedef long long ll;
typedef pair<int,int> pii; const int N=201;
const int mod=998244353;
const ll MOD=(0x7fffffffffffffffll/mod-mod)*mod;
const ll MAXN=1e18;
const int maxb=59;
ll qpow(ll a,int n)
{
ll ans=1;
for(;n;n>>=1,a=a*a%mod) if(n&1) ans=ans*a%mod;
return ans;
}
struct mat
{
int n,m;
int s[169][169];
mat() {clean();}
void clean() {memset(s,0,sizeof(s));n=m=0;}
};
mat c;
ll tmp[169][169];
mat operator * (const mat &a,const mat &b)
{
c.n=a.n; c.m=b.m;
for(int i=0;i<a.n;++i) for(int k=0;k<a.m;++k)
{
if(!a.s[i][k]) continue;
for(int j=0;j<b.m;++j) if((tmp[i][j]+=1ll*a.s[i][k]*b.s[k][j])>=MOD)
tmp[i][j]-=MOD;
//c.s[i][j]=(c.s[i][j]+1ll*a.s[i][k]*b.s[k][j]%mod)%mod;
}
for(int i=0;i<c.n;++i) for(int j=0;j<c.m;++j)
c.s[i][j]=tmp[i][j]%mod,tmp[i][j]=0;
return c;
}
mat matpw[70],X,V;
int id[N],is[N],tot=0,pw[15],K,m,k;
ll n; void wj()
{
#ifndef ONLINE_JUDGE
freopen("1.in","r",stdin);
freopen("1.out","w",stdout);
#endif
}
int main()
{
wj();
int i,j,opt,T;
T=read(); m=read(); k=read();
K=k+1; pw[0]=1;
for(i=1;i<=m;++i) pw[i]=pw[i-1]*K;
for(i=0;i<pw[m];++i)
{
int s=0;
for(j=0;j<m;++j) s+=i/pw[j]%K;
if(s<=k) is[tot]=i,id[i]=tot,tot++;
}
X.n=tot+1; X.m=1;
X.s[tot][0]=1; matpw[0].n=matpw[0].m=tot+1;
matpw[0].s[tot][tot]=1;
for(int idx=0;idx<tot;++idx)
{
int num=0;
for(i=0;i<m;++i) num+=is[idx]/pw[i]%K;
int inv=qpow(num+1,mod-2);
matpw[0].s[idx][tot]=inv; matpw[0].s[idx][idx]=inv;
int x=is[idx];
for(i=0;i<m;++i) if(x/pw[i]%K)
{
x-=pw[i];
if(i) x+=pw[i-1];
if(i&&num<k) x+=pw[m-1];
(matpw[0].s[idx][id[x]]+=1ll*inv*(is[idx]/pw[i]%K)%mod)%=mod;
x=is[idx];
}
}
for(i=1;i<=maxb;++i) matpw[i]=matpw[i-1]*matpw[i-1];
int ans=pw[m-1];
for(int cas=1;cas<=T;++cas)
{
scanf("%lld",&n);
V=X;
for(i=0;i<=maxb;++i) if(n&(1ll<<i)) V=matpw[i]*V;
printf("%d\n",V.s[id[ans]][0]);
}
return 0;
}

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. MySQL8.0错误日志Error log

    GreatSQL社区原创内容未经授权不得随意使用,转载请联系小编并注明来源. 理论知识 错误日志内容 错误日志包含mysqld启动和关闭的时间信息,还包含诊断消息,如服务器启动和关闭期间以及服务器运行 ...

  2. 多线程与高并发(五)—— 源码解析 ReentrantLock

    一.前言 ReentrantLock 是基于 AQS 实现的同步框架,关于 AQS 的源码在 这篇文章 已经讲解过,ReentrantLock 的主要实现都依赖AQS,因此在阅读本文前应该先了解 AQ ...

  3. php YII2空数组插入报错问题处理 Array to string conversion

    问题描述 前端传空数组 [],php接收后处理不当插入数据库时报错Array to string conversion 参数示例 { "id": 0, //ID整型 "t ...

  4. CF383C Propagating tree (线段树,欧拉序)

    \(tag\)没开够\(WA\)了一发... 求出\(dfs\)序,然后按深度分类更新与查询. #include <iostream> #include <cstdio> #i ...

  5. java学习第五天异常机制.day14

    异常处理机制 确保程序的正常执行.这种机制称为异常处理机制 异常对象 常用方法 方法介绍 toString 返回异常类型和异常信息 getMessage 返回异常信息 printStackTrace ...

  6. Chapter 09 - NSUndoManager (C#实现 + 全网原创)

    此例子针对NSDocument实现了tableview 每一行添加/删除的undo/redo,以及每一个单元格内容编辑的undo/redo.基于NSDocument类的实现.PersonModel + ...

  7. Lua环境搭建编译[Lua5.2+VS2010]

    这里是我编译的和一个测试Demo:http://download.csdn.net/detail/allh45601/6783653 大家如果看我下边说的不是很清楚,可以下载这个具体工程: 群:103 ...

  8. ADO.NET数据库开发

    ADO.NET博客  ADO.NET - 张果 - 博客园 (cnblogs.com) ADO.NET官方 ADO.NET | Microsoft Docs EntityFrameWork 开始使用 ...

  9. 理想汽车 x JuiceFS:从 Hadoop 到云原生的演进与思考

    理想汽车在 Hadoop 时代的技术架构 首先简单回顾下大数据技术的发展,基于我个人的理解,将大数据的发展分了4个时期: 第一个时期: 2006 年到 2008 年.2008 年左右,Hadoop 成 ...

  10. 【JDBC】学习路径2-编写第一个JDBC程序

    第一章:导入jar包 在未安装MySQL数据库的请务必安装,安装教程:[MySQL]从入门到掌握2-下载安装 connector/J下载地址:https://dev.mysql.com/downloa ...