题目链接

题面:

题意:
定义一个三元组的运算。 p = 998244353 p=998244353 p=998244353
( a 0 , a 1 , a 2 ) ( b 0 , b 1 , b 2 ) = (a_0,a_1,a_2) * (b_0,b_1,b_2)= (a0,a1,a2)(b0,b1,b2)=
( ( a 0 b 0 + a 1 b 2 + a 2 b 1 ) m o d <mtext>   </mtext> p , ( a 1 b 0 + a 2 b 2 + a 0 b 1 ) m o d <mtext>   </mtext> p , ( a 2 b 0 + a 0 b 2 + a 1 b 1 ) m o d <mtext>   </mtext> p ) ((a_0b_0+a_1b_2+a_2b_1) mod\space p,(a_1b_0+a_2b_2+a_0b_1) mod\space p,(a_2b_0+a_0b_2+a_1b_1) mod\space p) ((a0b0+a1b2+a2b1)mod p,(a1b0+a2b2+a0b1)mod p,(a2b0+a0b2+a1b1)mod p)

v是一个三元组 ( x , y , z ) (x,y,z) (x,y,z)
v n v^n vn,其中 n 大约是 2 400 2^{400} 2400数量级。

题解:

观察发现:单位元是 ( 1 , 0 , 0 ) (1,0,0) (1,0,0),具有结合律。可以用快速幂加速。
但是 n 的数量级太大了,无法直接快速幂。
玄学发现,循环节为 p 2 1 p^2-1 p21。(其实是看了别人的,应该是合理猜测+打表试验)
i n t 128 int128 int128直接冲。

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<string>
#include<queue>
#include<bitset>
#include<map>
#include<unordered_map>
#include<set>
#define ui unsigned int
#define ll long long
#define llu unsigned ll
#define ld long double
#define pr make_pair
#define pb push_back
#define lc (cnt<<1)
#define rc (cnt<<1|1)
#define len(x) (t[(x)].r-t[(x)].l+1)
#define tmid ((l+r)>>1)
using namespace std;
const int inf=0x3f3f3f3f;
const ll lnf=0x3f3f3f3f3f3f3f3f;
const double dnf=1e18;
const int mod=998244353;
const double eps=1e-8;
const double pi=acos(-1.0);
const int hp=13331;
const int maxn=100100;
const int maxm=100100;
const int up=100000;
const ll p32=1ll<<32;
const __int128 mod2=(__int128)mod*mod-1;

struct node
{
    ll a[3];
    void init(void)
    {
        memset(a,0,sizeof(a));
        a[0]=1;
    }
    node operator * (const node &b) const
    {
        node ans;
        ans.a[0]=(a[0]*b.a[0]+a[1]*b.a[2]+a[2]*b.a[1])%mod;
        ans.a[1]=(a[1]*b.a[0]+a[2]*b.a[2]+a[0]*b.a[1])%mod;
        ans.a[2]=(a[2]*b.a[0]+a[0]*b.a[2]+a[1]*b.a[1])%mod;
    	return ans;
	}
}v[maxn];

__int128 p2[500],e[25][maxn];

node mypow(node a,__int128 b)
{
	//node a 不能传引用,因为一个a会被多次使用 
    node ans;
    ans.init();
    while(b)
    {
        if(b&1) ans=ans*a;
        a=a*a;
        b>>=1;
    }
    return ans;
}

int main(void)
{
    ll n,m,q,z0,a,b;
    while(scanf("%lld%lld%lld%lld%lld%lld",&n,&m,&q,&z0,&a,&b)!=EOF)
    {
        ll z=z0;
        for(int i=1;i<=n;i++)
        {
            for(int j=0;j<=2;j++)
            {
                z=(z*a+b)%p32;
                v[i].a[j]=z%mod;
            }
        }

        p2[0]=1;
        for(int i=1;i<=400;i++)
            p2[i]=p2[i-1]*2%mod2;

        for(int k=1;k<=q;k++)
        {
            for(int i=1;i<=n;i++)
            {
                e[k][i]=0;
                for(int j=0;j<=m-1;j++)
                {
                    z=(z*a+b)%p32;
                    e[k][i]=(e[k][i]+z*p2[32*j])%mod2;
                }
            }
        }
       	for(int i=1;i<=q;i++)
        {
            node ans;
            ans.init();
            for(int j=1;j<=n;j++)
                ans=ans*mypow(v[j],e[i][j]);
            printf("%lld %lld %lld\n",ans.a[0],ans.a[1],ans.a[2]);
        }
    }
    return 0;
}