Codeforces - 551D. GukiZ and Binary Operations - 數學+矩陣快速冪

GukiZ and Binary Operations

題目鏈接

分類matrices combinatorics math number theory

1.題意概述

  • 給你一個長度爲n的數組a[1...n] ,滿足a[i]<2n ,並且有(a1 and a2) or (a2 and a3) or...or (an1 and an)=k ,答案取膜m

2.解題思路

  • 考慮它的二進制位,獨立計算每個位,假設dp[i]表示長度爲i的序列爲0的種數,那麼容易得到遞推式爲dp[i]=dp[i1]+dp[i2] ,這就類似於斐波那契數列,因爲是單組用例,我們可以考慮直接map存然後去遞推,當然最正統的做法是考慮用矩陣快速冪加速地去遞推:
    [dp[i]dp[i1]]=[1110]×[dp[i1]dp[i2]]

3.AC代碼

ll mod;
map<ll, ll> F;
ll quickmod(ll a, ll b, ll m) {
    ll ans = 1;
    while(b) { //用一個循環從右到左便利b的所有二進制位
        if(b & 1) { //判斷此時b[i]的二進制位是否爲1
            ans = (ans * a) % m; //乘到結果上,這裏a是a^(2^i)%m
            b--;//把該爲變0
        }
        b /= 2;
        a = a * a % m;
    }
    return ans;
}
ll Fib(ll n) {
    if(F.count(n))
        return F[n];
    ll k = n / 2;
    if(n % 2 == 0)
        return F[n] = (Fib(k) * Fib(k) % mod + Fib(k - 1) * Fib(k - 1) % mod) % mod;
    return F[n] = (Fib(k) * Fib(k + 1) % mod + Fib(k - 1) * Fib(k) % mod) % mod;
}
int main() {
    ll n, k, l;
    scanf("%I64d%I64d%I64d%I64d", &n, &k, &l, &mod);
    if(mod == 1 || k >= (1ULL << min(l, 63ll)) ) {
        puts("0");
    } else {
        F[0] = 1, F[1] = 1;
        ll res = 1;
        ll zero = Fib(n + 1);
        ll all = quickmod(2, n, mod);
        ll temp = (all - zero + mod) % mod;
        rep(i, 0, l) {
            if(k & 1)
                res = res * temp % mod;
            else res = res * zero % mod;
            k >>= 1;
        }
    //  printf("%I64d\n", all);
        printf("%I64d\n", res);
    }
    return 0;
}
發佈了350 篇原創文章 · 獲贊 47 · 訪問量 12萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章