CF1106F Lunar New Year and a Recursive Sequence(原根)(bsgs)(矩阵快速幂)

7 篇文章 0 订阅
3 篇文章 0 订阅

题意:给你b_i,且f_1=f_2=...f_(k-1)=1,然后有一条这样的递推式,然后告诉你f_n=m,求任意一个合法的f_k。

  • 首先,我们可以发现f_x的指数明显是一个符合矩阵快速幂的结果;
  • 我们如何把指数提取出来单纯的对指数运算出结果呢。很容易联想到了原根相关的东西;
  • 假设998244353的原根为g。有f_i=g^{a_i},即f_i=g^{a_i}=g^{a_i-1*b_1}g^{a_i-2*b_2}g^{a_i-3*b_3}...g^{a_i-k*b_k}(mod\textup{ P})
  • 把指数提取出来后,记得欧拉降幂a_i=\sum_{j=1}^{k}a_{i-j}*b_jmod \textup{ P-1}
  • 然后矩阵快速幂中的到结果x有a_i=x*a_k(modP-1)
  • 然后,然后取一下逆元就可以的到结果了。

注意P-1不是一定是素数

#include<algorithm>
#include<vector>
#include<iostream>
#include<math.h>
#include<cstring>
#include<string>
#include<stack>
#include<map>
#include<set>
#include<unordered_map>
#include<queue>
#include<assert.h>

#define qcin; ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define pb push_back
#define mp make_pair
#define clr(x) memset(x,0,sizeof x)
#define fmax(x) memset(x,0x3f,sizeof x)
#define finit(x) memset(x,-1,sizeof x)

#define dis(l,r) r-l+1
#define gstr(str) scanf("%s",str)
#define glen(str) strlen(str)
using namespace std;

namespace Input
{
    const int BUF = 65536;
    char buf[BUF + 1];
    char *head = buf, *tail = buf;
}
inline char inputchar()
{
    using namespace Input;
    if(head == tail)
        *(tail = (head = buf) + fread(buf, 1, BUF, stdin)) = 0;
    return *head++;
}
template<class T>
inline void io(T &ret)
{
    char ch = inputchar();
    while(ch < '0' || ch > '9')
        ch = inputchar();
    ret = ch - '0';
    ch = inputchar();
    while(ch >= '0' && ch <= '9')
    {
        ret = ret * 10 + ch - '0';
        ch = inputchar();
    }
}
typedef long long ll;

typedef pair<ll,ll>pll;
const int maxn = 1e5+10;
const int N = 110;
const int mod =  998244353-1;
const ll inf = 1e18;

typedef ll arr[maxn];
typedef char str[maxn];
void file(int x){if(x&&fopen("123.in","r")){freopen("123.in","r",stdin);}}

ll sz;
struct Mat{
    ll m[N][N];
    void zero(){
        memset(m,0,sizeof m);
    }
    void one(){
        for(int i=0;i<sz;i++){
            for(int j=0;j<sz;j++){
                m[i][j]=(i==j);
            }

        }
    }
    Mat operator *(const Mat &A)const{
        Mat ans;
        ans.zero();
        for(int i=0;i<sz;i++){
            for(int j=0;j<sz;j++){
                for(int k=0;k<sz;k++){
                    ans.m[i][j]=(ans.m[i][j]+m[i][k]*A.m[k][j]%mod)%mod;
                }
            }
        }
        return ans;
    }
    friend Mat operator ^ (Mat x,ll y){
        Mat ans;
        ans.one();
        while(y){
            if(y&1) ans=ans*x;
            x=x*x;y>>=1;
        }
        return ans;
    }
}seed;

int n,k,m,deg;

arr b;

ll qm(ll a,ll b,ll c){
    ll res=1;
    a%=c;
    while(b){
        if(b&1)res=res*a%c;
        a=a*a%c;b>>=1;
    }
    return res;

}
unordered_map<ll,ll>ma;
ll bsgs(ll a,ll b,ll c){
    ll sqr=sqrt(c)+1;
    ll now=1,step;
    for(ll i=0;i<sqr;i++){
        ll tmp=b*qm(now,c-2,c)%c;
        if(!ma.count(tmp)){
            ma[tmp]=i;
        }
        now=now*a%c;
    }
    step=now;
    now=1;
    for(ll i=0;i<c;i+=sqr){
        if(ma.count(now)){
            return i+ma[now];
        }
        now=now*step%c;
    }
    return -1;
}

ll ex_gcd(ll a,ll b,ll &x,ll &y){
    if(b==0){
        x=1;y=0;
        return a;
    }
    else{
        ll r=ex_gcd(b,a%b,y,x);
        y-=x*(a/b);
        return r;
    }
}

ll sol(ll a,ll b,ll c){
    if(b==0)return 0;
    ll k=__gcd(a,b);
    a/=k,b/=k;
    if(__gcd(a,c)!=1)return -1;
    ll res,tmp;
    ex_gcd(a,c,res,tmp);
    res=res*b%c;
    if(res<0)res+=c;
    return res;
}


int main(){
    file(1);
    io(k);
    sz=k;
    for(int i=0;i<k;i++){
        io(b[i]);
    }
    io(n);io(m);
    seed.zero();
    for(int i=0;i<k;i++){
        seed.m[0][i]=b[i];
    }
    for(int i=1;i<k;i++){
        seed.m[i][i-1]=1;
    }
    seed=seed^(n-k);
    deg=seed.m[0][0];
    ll fn=bsgs(3,m,mod+1);
    ll ans=sol(deg,fn,mod);
    if(ans==-1)puts("-1");
    else {
        printf("%lld\n",qm(3,ans,mod+1));
    }
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值