Skip to content
Logic Formatting

Logic Formatting

E. Xor-sequences 解析(思維、矩陣快速冪)

Posted on 2025 年 2 月 10 日2025 年 2 月 10 日 By jeff

今天我們來看看CF691E 題目連結

題目描述

給定 $n$ 個整數 $a_1, a_2, \dots, a_n$,求長度為 $k$ 的序列 $(x_1, x_2, \dots, x_k)$ 的數量,其中每個 $x_i$ 都從給定的數字中選取(相同數字若出現多次視為不同)。序列必須滿足:
$$ \forall, 1 \le i < k,\quad \mathrm{popcount}(x_i \oplus x_{i+1}) \equiv 0 \pmod{3}, $$ 其中 $\oplus$ 表示位元異或(XOR)運算,$\mathrm{popcount}(y)$ 表示 $y$ 的二進制表示中 1 的個數。


輸入格式

  • 第一行:兩個整數 $n$ 和 $k$ ($1 \le n \le 100$, $1 \le k \le 10^{18}$)。
  • 第二行:$n$ 個整數 $a_i$ ($0 \le a_i \le 10^{18}$)。

輸出格式

  • 輸出一個整數,代表滿足條件的序列數量模 $10^9+7$ 的結果。

前言

我真的以為這題是要先建一張圖,$a_i\oplus a_j\equiv0\pmod3$的話就連起來,然後問你說有幾種方式可以在這張圖走$k$步,但是完全想不出來怎麼做,看解答才發現是矩陣快速冪,太神奇了

想法

我也不知道這怎麼想到的,但是如果你想到說,令一個$z[i][j]$代表目前考慮到長度為$j$的XOR-sequence,並且結尾是$a[i]$的可能性的數量。
那麼如果$a[k]$是可以接在$a[i]$後面的數字,$z[k][j+1]$就可以從$z[i][j]$推出來。
具體來說:
$$ z[k][j+1] = \sum_{\text{avaliable }i}z[i][j] $$ 進一步說,如果不要限制$i$一定可以在$k$前面,公式會變成這樣:
$$ z[k][j+1] = \sum_{i}G_{i,k}z[i][j] $$ where $G_{ik}=1$ for $a[i]$可以接在$a[k]$前面
$G_{ik}=0$ otherwise
現在你就有可能看出來,這個操作是把$z[][j]$更新成$z[][j+1]$,所以我們可以不用存每一個長度$j$的$z[][j]$,而可以只保留一個$z[]$,代表目前考慮到的XOR-sequence長度的,每一個$a[i]$結尾的可能數量。
也就是說:
$$ z’[k] = \sum_{i}G_{i,k}z[i] $$ 然後因為$G$是symmetric的($G_{ij} = G_{ji}$)所以
$$ z’k = \sum{i}G_{k,i}z_i $$ 不過因為題目的$k$超大,所以如果你想說,這種方法只能sequential地更新而放棄這種做法,就失敗了。
這就是矩陣$G$乘上一個vector $z$的形式。所以對於更新$k$次$z$,可以用矩陣快速冪,只要$\lg(k)$次矩陣乘法就可以了(矩陣乘法$M_{n\times n}\cdot M_{n\times n}$的複雜度是$n^3$)
實作上要注意,記得計算的時候要$\pmod{10^9+7}$,還有__builtin_popcount是對int,要對long long用,要改用__builtin_popcountll

程式碼:

const int _n = 100 + 10;
ll n, k, a[_n];
struct Mat {
 public:
  int rlen, clen;
  vector<vector<int>> _a;
  Mat(int rlen, int clen) : rlen(rlen), clen(clen) {
    _a = vector<vector<int>>(rlen, vector<int>(clen, 0));
  }
  Mat operator*(const Mat& rhs) const {
    Mat res(this->rlen, rhs.clen);
    rep(i, 0, res.rlen) rep(j, 0, res.clen) {
      res._a[i][j] = 0;
      rep(k, 0, this->clen) res._a[i][j] = (1ll * res._a[i][j] + 1ll * (_a[i][k] % mod) * (rhs._a[k][j] % mod)) % mod;
    }
    return res;
  }
  Mat operator^(ll b) {
    Mat res(rlen, clen), tmp = *this;
    assert(rlen == clen);
    rep(i, 0, rlen) {
      res._a[i][i] = 1;
    }
    while (b) {
      if (b & 1ll) res = res * tmp;
      b >>= 1ll;
      tmp = tmp * tmp;
    }
    return res;
  }
};
main(void) {
  ios_base::sync_with_stdio(0);
  cin.tie(0);
  cout.tie(0);
  cin >> n >> k;
  Mat G(n, n);
  Mat z(n, 1);
  rep(i, 0, n) {
    cin >> a[i];
    z._a[i][0] = 1;
  }

  rep(i, 0, n) {
    rep(j, 0, n) {
      if (__builtin_popcountll(a[i] ^ a[j]) % 3 == 0) {
        G._a[i][j] = 1;
      }
    }
  }
  z = (G ^ (k - 1)) * z;
  ll ans = 0;
  rep(i, 0, n) {
    ans = (1ll * ans + 1ll * z._a[i][0]) % mod;
  }
  cout << ans << '\n';
  return 0;
}

標頭、模板請點Submission看 Submission

ojcode codeforceojcode思維矩陣快速冪

文章導覽

Previous post
Next post

發佈留言 取消回覆

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *

近期文章

  • B. Kyoya and Permutation 解析(思維、數論、DP)
  • G. Guess One Character 解析(思維)
  • E. The Road to Berland is Paved With Good Intentions 解析(思維、2-SAT、SCC、拓樸排序)
  • E. Xor-sequences 解析(思維、矩陣快速冪)
  • LeetCode. First Missing Positive 解析(思維)

近期留言

尚無留言可供顯示。

彙整

  • 2025 年 2 月
  • 2025 年 1 月

分類

  • ojcode
©2026 Logic Formatting | WordPress Theme by SuperbThemes