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

题面在这里

题意

有一个\(Boss\)和他血量为\(m\)的随从奴隶主,每当奴隶主受到攻击且不死,并且\(Boss\)的随从个数\(<k\)时,就会新召唤一个血量为\(m\)的奴隶主。每次攻击\(Boss\)和每个奴隶主的概率是相同的,求\(n\)步后期望对\(Boss\)造成的伤害。

\(T\le1000,n\le10^{18},m\le3,k\le8\)

sol

---

看到\(m<=3,k<=8\)的良心数据肯定是状压啦

通过暴搜可以得出状态最多只会有\(164\)种

并且两个状态之间的转移是固定的

因此我们考虑矩阵快速幂

但是...时间复杂度为\(O(T164^3logn)\)跑得过?

因此,优化这种矩乘的方法横空出世:

由于一个向量乘上一个矩阵的复杂度是\(O(n^2)\)的,因此我们把\(2^i\)的矩阵全部预处理出来,

最后再使用倍增的手段进行合并

时间复杂度变成了\(O(164^3logn+T164^2logn)\),非常需要卡常。。。

下面代码不保证能一次通过

代码

#include<bits/stdc++.h>
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<iomanip>
#include<cstring>
#include<complex>
#include<vector>
#include<cstdio>
#include<string>
#include<bitset>
#include<cmath>
#include<queue>
#include<stack>
#include<map>
#include<set>
#define mp make_pair
#define pb push_back
#define RG register
#define il inline
using namespace std;
typedef unsigned long long ull;
typedef vector<int>VI;
typedef long long ll;
typedef double dd;
const dd eps=1e-10;
const int mod=998244353;
const int N=50010;
il ll read(){
    RG ll data=0,w=1;RG char ch=getchar();
    while(ch!=‘-‘&&(ch<‘0‘||ch>‘9‘))ch=getchar();
    if(ch==‘-‘)w=-1,ch=getchar();
    while(ch<=‘9‘&&ch>=‘0‘)data=data*10+ch-48,ch=getchar();
    return data*w;
}

il void file(){
    //freopen("a.in","r",stdin);
    //freopen("a.out","w",stdout);
}

ll poww(ll a,ll b){
    RG ll ret=1;
    for(a%=mod;b;b>>=1,a=a*a%mod)
        if(b&1)ret=ret*a%mod;
    return ret;
}

ll n,Tim,m,k,ans,tot;
int a[4],t[4];
int b[9][9][9];

struct node{
    int x,y,z,id,p;
    il void print(){printf("x=%d,y=%d,z=%d,id=%d,p=%d\n",x,y,z,id,p);}
};
vector<node>sol;
int S[170],z[170];

struct matrix{
    int a[170][170];
    il void clear(){memset(a,0,sizeof(a));}
    il void print(){
        for(RG int i=1;i<=tot;i++,puts(""))
            for(RG int j=1;j<=tot;j++)
                printf("%d ",a[i][j]);
        puts("");
    }
    int* operator [](int x){return a[x];}
}T[61],P;

il void dfs(int s[]){
    int p[4];
    b[s[1]][s[2]][s[3]]=++tot;
    P[b[s[1]][s[2]][s[3]]][b[s[1]][s[2]][s[3]]]=poww(s[1]+s[2]+s[3]+1,mod-2)%mod;
    sol.pb((node){s[1],s[2],s[3],tot,poww(s[1]+s[2]+s[3]+1,mod-2)});

    for(RG int i=1;i<=3;i++)
        if(s[i]){//枚举要打的是哪一个
            for(RG int j=1;j<=3;j++)p[j]=s[j];
            if(s[1]+s[2]+s[3]<k){if(i!=1){p[m]++;p[i-1]++;}p[i]--;}
            else{p[i]--;if(i!=1)p[i-1]++;}
            RG int add=1ll*s[i]*poww(s[1]+s[2]+s[3]+1,mod-2)%mod;
            if(!b[p[1]][p[2]][p[3]])dfs(p);
            (P[b[s[1]][s[2]][s[3]]][b[p[1]][p[2]][p[3]]]+=add)%=mod;
        }
}

il matrix times1(RG matrix x,RG matrix y){
    RG matrix z;z.clear();
    for(RG int i=1;i<=tot;i++)
        for(RG int j=1;j<=tot;j++)
            for(RG int k=1;k<=tot;k++)
                z[i][k]=(z[i][k]+1ll*x[i][j]*y[j][k]%mod)%mod;
    return z;
}

il void times2(RG matrix y){
    memset(z,0,sizeof(z));
    for(RG int j=1;j<=tot;j++)
        for(RG int k=1;k<=tot;k++)
            z[k]=(z[k]+1ll*S[j]*y[j][k]%mod)%mod;
    for(RG int i=1;i<=tot;i++)S[i]=z[i];
}

il void DP(ll n){
    ans=0;memset(S,0,sizeof(S));S[1]=1;
    for(RG ll i=1;(((ll)1)<<(i-1))<=n;i++)
        if((n&(((ll)1)<<(i-1)))==(((ll)1)<<(i-1)))
            times2(T[i]);
    ans=S[tot];
}

int main()
{
    file();Tim=read();m=read();k=read();a[m]=1;dfs(a);tot++;
    for(RG int i=1;i<=tot-1;i++)P[i][tot]=sol[i-1].p;P[tot][tot]=1;
    T[1]=P;for(RG int i=2;i<=60;i++)T[i]=times1(T[i-1],T[i-1]);
    while(Tim--){n=read();DP(n);printf("%lld\n",ans);}
    return 0;
}

原文地址:https://www.cnblogs.com/cjfdf/p/8436163.html

时间: 2024-10-08 01:16:38

[清华集训]小 Y 和恐怖的奴隶主的相关文章

[LOJ#2325]「清华集训 2017」小Y和恐怖的奴隶主

[LOJ#2325]「清华集训 2017」小Y和恐怖的奴隶主 试题描述 "A fight? Count me in!" 要打架了,算我一个. "Everyone, get in here!" 所有人,都过来! 小Y是一个喜欢玩游戏的OIer.一天,她正在玩一款游戏,要打一个Boss. 虽然这个Boss有 \(10^{100}\) 点生命值,但它只带了一个随从--一个只有 \(m\) 点生命值的"恐怖的奴隶主". 这个"恐怖的奴隶主&qu

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

哇这题剧毒,卡了好久常数才过T_T 设$f(i,s)$为到第$i$轮攻击,怪物状态为$s$时对boss的期望伤害,$sum$为状态$s$所表示的怪物个数,得到朴素的DP方程$f(i,s)=\sum \frac{1}{sum+1}*(f(i+1,s')+[s==s'])$ 状态数只有$C_{8+3}^3=165$个,所以就可以矩乘优化啦.再加上一个用于转移的$1$,矩阵大小是$166*166$的,因为多组询问,所以可以先把$2$的所有次幂的矩阵都预处理出来. 然后会发现复杂度是$O(T*166^3

【清华集训】小Y和地铁

题目: 小 $\rm Y$ 是一个爱好旅行的 $\rm OIer$.一天,她来到了一个新的城市.由于不熟悉那里的交通系统,她选择了坐地铁.她发现每条地铁线路可以看成平面上的一条曲线,不同线路的交点处一定会设有换乘站.通过调查得知,没有线路是环线,也没有线路与自身相交.任意两条不同的线路只会在若干个点上相交,没有重合的部分,且没有三线共点的情况.即,如图所示的情况都是不存在的: 小 Y 坐着地铁 $0$ 号线,路上依次经过了 $n$ 个换乘站.她记下了每个换乘站可以换乘的线路编号,发现每条线路与她

【UOJ274】【清华集训2016】温暖会指引我们前行 LCT

[UOJ274][清华集训2016]温暖会指引我们前行 任务描述 虽然小R住的宿舍楼早已来了暖气,但是由于某些原因,宿舍楼中的某些窗户仍然开着(例如厕所的窗户),这就使得宿舍楼中有一些路上的温度还是很低. 小R的宿舍楼中有n个地点和一些路,一条路连接了两个地点,小R可以通过这条路从其中任意一个地点到达另外一个地点.但在刚开始,小R还不熟悉宿舍楼中的任何一条路,所以他会慢慢地发现这些路,他在发现一条路时还会知道这条路的温度和长度.每条路的温度都是互不相同的. 小R需要在宿舍楼中活动,每次他都需要从

bzoj 4736 /uoj274【清华集训2016】温暖会指引我们前行 lct

[清华集训2016]温暖会指引我们前行 统计 描述 提交 自定义测试 寒冬又一次肆虐了北国大地 无情的北风穿透了人们御寒的衣物 可怜虫们在冬夜中发出无助的哀嚎 “冻死宝宝了!” 这时 远处的天边出现了一位火焰之神 “我将赐予你们温暖和希望!” 只见他的身体中喷射出火焰之力 通过坚固的钢铁,传遍了千家万户 这时,只听见人们欢呼 “暖气来啦!” 任务描述 虽然小R住的宿舍楼早已来了暖气,但是由于某些原因,宿舍楼中的某些窗户仍然开着(例如厕所的窗户),这就使得宿舍楼中有一些路上的温度还是很低. 小R的

「清华集训2014」矩阵变换

「清华集训2014」矩阵变换 解题思路 问题转化为找一个行与选的数字的完美匹配,记 \(pos[i][j]\) 为数字 \(i\) 在第 \(j\) 行的出现位置,要求不存在匹配边 \((a,b),(c,d)\) 使得 \(pos[b][a] < pos[b][c]\ \& \ pos[d][c] > pos[b][c]\) . 观察发现,这个式子相当于让一条边的权值看做 \(pos[x][y]\) ,当存在一个行与一个数没有匹配但是强行让它们匹配后数的权值会变大,行的权值会变小,这个

清华集训2014 做题记录

清华集训2014做题记录 已完成 [清华集训2014]玛里苟斯 [清华集训2014]主旋律 [清华集训2014]奇数国 [清华集训2014]矩阵变换 [清华集训2014]sum [清华集训2014]虫逢 [清华集训2014]玄学 [清华集训2014]文学 未完成 [清华集训2014]卡常数 [清华集训2014]简单回路 [清华集训2014]Router [清华集训2014] Breaking Bomber 写一题要膜一题题解,膜完题解膜代码,膜完代码膜指导,膜了好几天了还有四个题没做. [清华集

2017.11.26【清华集训2017】模拟

T1 5483. [清华集训2017模拟11.26]简单路径T2 5484. [清华集训2017模拟11.26]快乐树T3 5485. [清华集训2017模拟11.26]字符串 T1 结论题,结论很显然任意两条路径权异或后,会将两条路径的交的贡献删去.然后用个桶存一下出现过的异或和,暴力判一下就可以了 code 1 #include<cstdio> 2 #include<cmath> 3 #include<cstring> 4 #include<algorithm

[LOJ#2327]「清华集训 2017」福若格斯

[LOJ#2327]「清华集训 2017」福若格斯 试题描述 小d是4xx9小游戏高手. 有一天,小d发现了一个很经典的小游戏:跳青蛙. 游戏在一个 \(5\) 个格子的棋盘上进行.在游戏的一开始,最左边的两个格子上各有一个向右的青蛙,最右边的两个格子上各有一个向左的青蛙. 每次移动可以选取一个青蛙,向这只青蛙的前方移动一格到空格子中或跳过前方的一个不同朝向的青蛙并移动到空格子中. 为了使你更好地理解这个游戏,我们下发了一个游戏demo作为参考(注意:这个demo中的棋盘大小和题目中并不相同).