zoukankan      html  css  js  c++  java
  • [清华集训]小 Y 和*的奴隶主

    题面在这里

    题意

    有一个(Boss)和他血量为(m)的随从奴隶主,每当奴隶主受到攻击且不死,并且(Boss)的随从个数(<k)时,就会新召唤一个血量为(m)的奴隶主。每次攻击(Boss)和每个奴隶主的概率是相同的,求(n)步后期望对(Boss)造成的伤害。
    (Tle1000,nle10^{18},mle3,kle8)
    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
    ",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
    ",ans);}		
    	return 0;
    }
    
    
  • 相关阅读:
    Codeforces Round #609 (Div. 2)
    Educational Codeforces Round 78 (Rated for Div. 2)
    Codeforces
    crontab
    C6 C7的开机启动流程
    平均负载压力测试
    ps 和 top
    if判断
    使用3种协议搭建本地yum仓库
    linux rpm包
  • 原文地址:https://www.cnblogs.com/cjfdf/p/8436163.html
Copyright © 2011-2022 走看看