1. 程式人生 > >洛谷4714(數論+米勒羅賓)

洛谷4714(數論+米勒羅賓)

log names cpp 代碼 anti class turn operator per

看到沒有矩陣乘法的題解 一開始我是因為被推薦矩陣乘法才來寫這一題的
樓下大佬們的數學公式很強 學到了
矩陣乘法是用矩陣優化達到遞推logN解法的一種算法(大佬們無視)
可以用矩陣做的題推薦一道 https://nanti.jisuanke.com/t/16442
遞推式是 設a()表示已經越獄的 b()表示沒有越獄的
則 a(i)=a(i-1)m+b(i-1);表示已經越獄的最後一個人是什麽都可以 沒越獄的只能和倒數第二個一樣
b(i)=(a(i-1)+b(i-1))
m-a(i)=(m-1)*b(i-1);有m^n種可能 相減即可
b(1)=m;
下面貼代碼

#include<iostream>
#include<cstdio>
using namespace std;
typedef long long ll;//不打long long 會WA
const ll MOD=100003;
ll i,j,n,m;
struct node{
    ll s[2][2];
    node(){
    for(int i=0;i<=1;i++)
            for(int j=0;j<=1;j++)
                s[i][j]=0;
}//矩陣初始為0;

    node operator * (const node& b){
        node all;
        for(int i=0;i<=1;i++)
            for(int j=0;j<=1;j++)
                for(int k=0;k<=1;k++){
                    all.s[i][j]+=s[i][k]*b.s[k][j];//矩陣乘法 不知道戳百科 (行的每個元素*列的每個元素)
                    all.s[i][j]%=MOD;//不能忘了取模
                }
        return all;//return矩陣
    }
}a,b,ans;
node qpow(node t,ll k){
    node w;w.s[0][0]=0;w.s[0][1]=m;//快速冪
    for(ll i=k;i;i>>=1,t=t*t)
    if(i&1)w=w*t;return w;
}
int main(){
    scanf("%lld%lld",&m,&n);
    a.s[0][0]=m;a.s[0][1]=0;//
    a.s[1][0]=1;a.s[1][1]=m-1;//矩陣的初始化
    ans=qpow(a,n-1);
    printf("%lld",ans.s[0][0]);//輸出
}

洛谷4714(數論+米勒羅賓)