[LOJ2325][清华集训 2017]小Y和恐怖的奴隶主 矩阵乘法+奇技淫巧

首先发现状态之和每种体力值的奴隶主个数有关,计算一下发现状态数最多165,于是搞出转移矩阵,设 fi,S 表示i轮时状态为 S ,之后的期望, num 为奴隶主个数 +1 ,转移就是 fi,S=1num+ssfi+1,S 然后 O(T1653logn) 矩阵快速幂,不过这样会TLE。
如下技巧使用于询问很多的情况:预处理矩阵的 2t 次幂,然后每次询问乘上对应的那些矩阵即可,因为向量乘上矩阵是 O(1652) 的,所以复杂度优化到 O(1653logn+T1652logn)
还有一个卡常的技巧,就是搞个模数的大倍数。。。然后减少取模次数。。。
代码:

#include
#include
#include
#define ll unsigned long long
using namespace std;
const int mod=998244353;
const ll P=16940360401038606353llu;
ll n,inv[10],ans[170],tmp[170];
int m,K,ha[9][9][9];
ll ksm(ll a,int b){ll r=1;for(a%=mod;b;b>>=1){if(b&1)r=r*a%mod;a=a*a%mod;}return r;}
inline void up(ll &a,ll b){a+=b,a>=P?a-=P:0;} 
struct matrix
{
    ll a[170][170],h,w;
    void init(int rh,int rw){h=rh;w=rw;memset(a,0,sizeof(a));}
    matrix operator *(matrix &b)
    {
        matrix re;
        re.init(h,b.w);
        for(int i=1;i<=h;i++)
            for(int j=1;j<=b.w;j++)
            {
                for(int k=1;k<=w;k++)
                    up(re.a[i][j],a[i][k]*b.a[k][j]);
                re.a[i][j]%=mod;    
            }
        return re;          
    }
}d[65];
void mul(matrix p,ll* q)
{
    memset(tmp,0,sizeof(tmp));
    for(int i=1;i<=p.h;i++)
    {
        for(int k=1;k<=p.w;k++)
            up(tmp[i],p.a[i][k]*q[k]);
        tmp[i]%=mod;    
    }
    memcpy(q,tmp,sizeof(tmp));      
}
int main()
{
    int ca;
    scanf("%d%d%d",&ca,&m,&K);
    for(int i=1;i<=K+1;i++)
        inv[i]=ksm(i,mod-2);
    int num=0;
    for(int k=0;k<=(m>2?K:0);k++)
        for(int j=0;j<=(m>1?K-k:0);j++)
            for(int i=0;i<=(m?K-j-k:0);i++) 
                ha[i][j][k]=++num;      
    for(int i=0;i<=63;i++)
        d[i].init(num+1,num+1);             
    for(int i=0;i<=(m?K:0);i++)
        for(int j=0;j<=(m>1?K-i:0);j++)
            for(int k=0;k<=(m>2?K-i-j:0);k++)               
            {
                int t=i+j+k,g=ha[i][j][k],b=t1];
                if(m==1)
                {
                    d[0].a[g][ha[i-1][0][0]]=P*i%mod;
                }
                if(m==2)
                {
                    if(i) d[0].a[g][ha[i-1][j][0]]=P*i%mod;
                    if(j) d[0].a[g][ha[i+1][j-1+b][0]]=P*j%mod;
                }
                if(m==3)
                {
                    if(i) d[0].a[g][ha[i-1][j][k]]=P*i%mod;
                    if(j) d[0].a[g][ha[i+1][j-1][k+b]]=P*j%mod;
                    if(k) d[0].a[g][ha[i][j+1][k-1+b]]=P*k%mod;
                }
                d[0].a[g][g]=d[0].a[g][num+1]=P;
            }

    d[0].a[num+1][num+1]=1;             
    for(int i=1;i<=60;i++)
        d[i]=d[i-1]*d[i-1];     
    while(ca--)
    {
        scanf("%lld",&n);
        memset(ans,0,sizeof(ans));
        ans[num+1]=1;
        for(int k=0;k<=60;k++)
            if(n&(1ll<if(m==1)printf("%lld\n",ans[ha[1][0][0]]);
        if(m==2)printf("%lld\n",ans[ha[0][1][0]]);
        if(m==3)printf("%lld\n",ans[ha[0][0][1]]);      
    }
    return 0;
}

你可能感兴趣的:(dp,线性代数,奇技淫巧)