【2025 深圳大学-腾讯云程序设计竞赛(热身赛)】题解

比赛链接

A. Cloud Studio的共享连接

题目大意 && Solution

给定 T T T 组长度均为 12 12 12 的字符串 s s s

对每个 s s s,将其按从左到右的顺序两两分组形成 6 6 6 A S C I I \rm{ASCII} ASCII 码,对这 6 6 6 A S C I I \rm{ASCII} ASCII 码都 + 50 +50 +50,作为输出的字符串(即长度为 6 6 6 的新字符串)。

直接模拟即可。

时间复杂度 O ( 12 ⋅ T ) O(12 \cdot T) O(12T)

C++ Code

#include <bits/stdc++.h>using i64 = long long;
using u64 = unsigned long long;
using u32 = unsigned;
using i80 = __int128_t;
using u80 = unsigned __int128_t;
using f64 = double;
using f80 = long double;
using i16 = short;
using u16 = unsigned short;constexpr f64 pi = std::numbers::pi;std::mt19937 rng(std::chrono::steady_clock::now().time_since_epoch().count());void solve() {std::string s;std::cin >> s;std::string ans;for (int i = 0; i + 2 <= s.size(); i += 2) {ans += char(std::stoi(s.substr(i, 2)) + 50);}std::cout << ans << "\n";
}int main() {std::ios::sync_with_stdio(false);std::cin.tie(nullptr);std::cout << std::fixed << std::setprecision(12);int T = 1;std::cin >> T;while (T--) {solve();}return 0;
}

B. 都是绘绘,都是早凉的老婆

题目大意

给定 T T T 组数据,每组数据给定一棵树。

对于每棵 n n n 个节点的树, A l i c e \rm{Alice} Alice B o b \rm{Bob} Bob 想玩博弈论,但是不想玩得太简单,于是让 B o b \rm{Bob} Bob 一开始选择一个点集 V V V,两人就在 V V V生成子图 G = ( V , E ) G = (V, E) G=(V,E) 上开始玩, A l i c e \rm{Alice} Alice 先手。

当前玩家可以选择删掉 G G G 中的一条边,也可以删掉一个点及其所有相连的边。不能操作的玩家将输掉比赛;特别的,若 G G G 为空,视为 B o b \rm{Bob} Bob 胜利。

当然这都不重要,因为这是 2023 C C P C \rm{2023CCPC} 2023CCPC 哈尔滨的题目,结论是:

奇数个点的树的 S G \rm{SG} SG 值为 1 1 1,偶数个点的树 S G \rm{SG} SG 值为 2 2 2 B o b \rm{Bob} Bob 选择的点集 V V V 只需要满足每个连通块的 S G \rm{SG} SG 值异或起来等于 0 0 0 就有必胜策略。

特别的,空集的 S G \rm{SG} SG 值为 0 0 0

在此基础上,本题想问: B o b \rm{Bob} Bob 有多少种方案选择点集 V V V 能够获胜。

两种方案不同,当且仅当两次选择的点集 V V V 不同。答案对 998244353 998244353 998244353 取模。

数据范围

  • 1 ≤ ∑ n ≤ 1 0 6 1 \leq \sum n \leq 10^6 1n106

Solution

我们把异或起来为零翻译一下,可以得到:

  • ∣ V ∣ |V| V 一定为偶数,因为最终异或值要为 0 0 0,即不论出现多少个 1 1 1 还是 2 2 2,都要求出现偶数个奇数点连通块或偶数个偶数点连通块;
  • ∣ E ∣ |E| E 一定为偶数,因为对每个连通块来说都有 ∣ E i ∣ = ∣ V i ∣ − 1 |E_i| = |V_i| - 1 Ei=Vi1(树中拆出来的连通块的性质)。

定义 d p [ x ] [ 0 / 1 ] [ 0 / 1 ] [ 0 / 1 ] \rm{dp}[x][0/1][0/1][0/1] dp[x][0/1][0/1][0/1] 为总方案数,细节如下。

  • 对当前结点 x x x
  • 第一个 0 / 1 0/1 0/1 表示 不选 / 选 \rm{不选}/\rm{选} 不选/ x x x 加入 V V V
  • 第二个 0 / 1 0/1 0/1 表示已经选择的点集 V V V 大小的奇偶, ∣ V ∣ |V| V 为偶(奇)时为 0 0 0 1 1 1),
  • 第三个 0 / 1 0/1 0/1 表示由已选择点集 V V V 导出的边集 E E E 大小的奇偶, ∣ E ∣ |E| E 为偶(奇)时为 0 0 0 1 1 1)。

下面我们定义 二维矩阵的三个运算 ⊕ \oplus 为异或运算)。

  • 加法 + + +:与正常的矩阵一样,对于 c = a + b c = a + b c=a+b,有 c [ i ] [ j ] = a [ i ] [ j ] + b [ i ] [ j ] , 0 ≤ i , j < 2. c[i][j] = a[i][j] + b[i][j], \ 0 \leq i, j < 2. c[i][j]=a[i][j]+b[i][j], 0i,j<2.
  • 乘法 × \times ×:乘法被重新定义,对于 c = a × b c = a \times b c=a×b,有 c [ i ⊕ u ] [ j ⊕ v ] = c [ i ⊕ u ] [ j ⊕ v ] + a [ i ] [ j ] × b [ u ] [ v ] , 0 ≤ i , j , u , v < 2. c[i \oplus u][j \oplus v] = c[i \oplus u][j \oplus v] + a[i][j] \times b[u][v], \ 0 \leq i, j, u, v < 2. c[iu][jv]=c[iu][jv]+a[i][j]×b[u][v], 0i,j,u,v<2. 这里的乘法意思是: i i i u u u 分别表示点集大小 ∣ V ∣ |V| V 的奇偶, j j j v v v 分别表示边集大小 ∣ E ∣ |E| E 的奇偶,这样合并二者的方案数只需要枚举 2 4 2^4 24 种情况;而最终新的奇偶性就是 i ⊕ u i \oplus u iu j ⊕ v j \oplus v jv
  • 取反 ! ! !:也是重新定义,对于 c = ! a c = \ !a c= !a,有 c [ i ] [ j ⊕ 1 ] = a [ i ] [ j ] , 0 ≤ i , j < 2. c[i][j \oplus 1] = a[i][j], \ 0 \leq i, j < 2. c[i][j1]=a[i][j], 0i,j<2. 这里的取反意思是: i i i 表示点集 ∣ V ∣ |V| V 大小的奇偶, j j j 表示边集大小 ∣ E ∣ |E| E 的奇偶,当我确定我加入了 1 1 1 条新的边,边集的奇偶性就发生改变,所以最后一个维度的方案数应该调换。

下面考虑状态转移。

  • d p [ x ] [ 0 ] = d p [ x ] [ 0 ] × ( d p [ y ] [ 0 ] + d p [ y ] [ 1 ] ) \rm{dp[x][0] = dp[x][0] \times (dp[y][0] + dp[y][1])} dp[x][0]=dp[x][0]×(dp[y][0]+dp[y][1]),这表示对于 x x x 及其子树,不选择 x x x,那么选择 y y y 不会 引起边的奇偶性变化,只要将其合并到 d p [ x ] [ 0 ] \rm{dp[x][0]} dp[x][0] 中即可;
  • d p [ x ] [ 1 ] = d p [ x ] [ 1 ] × ( d p [ y ] [ 0 ] + ! d p [ y ] [ 1 ] ) \rm{dp[x][1] = dp[x][1] \times (dp[y][0] \ + \ !dp[y][1])} dp[x][1]=dp[x][1]×(dp[y][0] + !dp[y][1]),这表示对于 x x x 及其子树,选择了 x x x,那么选择 y y y 引起边的奇偶性变化,需要取反并将其合并到 d p [ x ] [ 1 ] \rm{dp[x][1]} dp[x][1]

初始化:对于 x ∈ [ 1 , n ] x \in [1, n] x[1,n],均有 d p [ x ] [ 0 ] [ 0 ] [ 0 ] = d p [ x ] [ 1 ] [ 1 ] [ 0 ] = 1 \rm{dp[x][0][0][0] = dp[x][1][1][0] = 1} dp[x][0][0][0]=dp[x][1][1][0]=1,分别表示 0 0 0 个点 0 0 0 条边,以及 1 1 1 个点 0 0 0 条边,都是一种方案。

最终答案 d p [ 0 ] [ 0 ] [ 0 ] [ 0 ] + d p [ 0 ] [ 1 ] [ 0 ] [ 0 ] \rm{dp[0][0][0][0] + dp[0][1][0][0]} dp[0][0][0][0]+dp[0][1][0][0]

时间复杂度 O ( 2 4 ∑ n ) O(2^4\sum \rm{n}) O(24n)

  • 常数会稍大, 1 0 6 10^6 106 的递归栈消耗很大。

C++ Code

#include <bits/stdc++.h>using i64 = long long;
using u64 = unsigned long long;
using u32 = unsigned;
using i80 = __int128_t;
using u80 = unsigned __int128_t;
using f64 = double;
using f80 = long double;
using i16 = short;
using u16 = unsigned short;constexpr f64 pi = std::numbers::pi;std::mt19937 rng(std::chrono::steady_clock::now().time_since_epoch().count());template<class T>
constexpr T power(T a, i64 b) {T res = 1;for (; b; b /= 2, a *= a) {if (b % 2) {res *= a;}}return res;
}
template<int P>
struct MInt {int x;constexpr MInt() : x{} {}constexpr MInt(i64 x) : x{norm(x % getMod())} {}static int Mod;constexpr static int getMod() {if (P > 0) {return P;} else {return Mod;}}constexpr static void setMod(int Mod_) {Mod = Mod_;}constexpr int norm(int x) const {if (x < 0) {x += getMod();}if (x >= getMod()) {x -= getMod();}return x;}constexpr int val() const {return x;}explicit constexpr operator int() const {return x;}constexpr MInt operator-() const {MInt res;res.x = norm(getMod() - x);return res;}constexpr MInt inv() const {assert(x != 0);return power(*this, getMod() - 2);}constexpr MInt &operator*=(MInt rhs) & {x = 1LL * x * rhs.x % getMod();return *this;}constexpr MInt &operator+=(MInt rhs) & {x = norm(x + rhs.x);return *this;}constexpr MInt &operator-=(MInt rhs) & {x = norm(x - rhs.x);return *this;}constexpr MInt &operator/=(MInt rhs) & {return *this *= rhs.inv();}friend constexpr MInt operator*(MInt lhs, MInt rhs) {MInt res = lhs;res *= rhs;return res;}friend constexpr MInt operator+(MInt lhs, MInt rhs) {MInt res = lhs;res += rhs;return res;}friend constexpr MInt operator-(MInt lhs, MInt rhs) {MInt res = lhs;res -= rhs;return res;}friend constexpr MInt operator/(MInt lhs, MInt rhs) {MInt res = lhs;res /= rhs;return res;}friend constexpr std::istream &operator>>(std::istream &is, MInt &a) {i64 v;is >> v;a = MInt(v);return is;}friend constexpr std::ostream &operator<<(std::ostream &os, const MInt &a) {return os << a.val();}friend constexpr bool operator==(MInt lhs, MInt rhs) {return lhs.val() == rhs.val();}friend constexpr bool operator!=(MInt lhs, MInt rhs) {return lhs.val() != rhs.val();}
};template<>
int MInt<0>::Mod = 998244353;template<int V, int P>
constexpr MInt<P> CInv = MInt<P>(V).inv();constexpr int P = 998244353;
using Z = MInt<P>;using Vector = std::array<Z, 2>;
using Matrix = std::array<Vector, 2>;
using Tensor = std::array<Matrix, 2>;Matrix operator+(const Matrix &a, const Matrix &b) {Matrix c{};for (int i = 0; i < 2; i++) {for (int j = 0; j < 2; j++) {c[i][j] = a[i][j] + b[i][j];}}return std::move(c);
}
Matrix operator*(const Matrix &a, const Matrix &b) {Matrix c{};for (int i = 0; i < 2; i++) {for (int j = 0; j < 2; j++) {if (a[i][j] == 0) {continue;}for (int u = 0; u < 2; u++) {for (int v = 0; v < 2; v++) {c[i ^ u][j ^ v] += a[i][j] * b[u][v];}}}}return std::move(c);
}
Matrix operator!(const Matrix &a) {auto c = a;for (int i = 0; i < 2; i++) {std::swap(c[i][0], c[i][1]);}return std::move(c);
}void solve() {int n;std::cin >> n;std::vector<std::vector<int>> adj(n);for (int i = 1; i < n; i++) {int u, v;std::cin >> u >> v;u--, v--;adj[u].push_back(v);adj[v].push_back(u);}std::vector<Tensor> dp(n);auto dfs = [&](auto &&self, int x) -> void {dp[x][0][0][0] = 1;dp[x][1][1][0] = 1;for (int y: adj[x]) {adj[y].erase(std::ranges::find(adj[y], x));self(self, y);auto res = dp[y][0] + dp[y][1];dp[x][0] = dp[x][0] * res;res = dp[y][0] + !dp[y][1];dp[x][1] = dp[x][1] * res;}};dfs(dfs, 0);auto ans = dp[0][0] + dp[0][1];std::cout << ans[0][0] << "\n";
}int main() {std::ios::sync_with_stdio(false);std::cin.tie(nullptr);std::cout << std::fixed << std::setprecision(12);int T = 1;std::cin >> T;while (T--) {solve();}return 0;
}

C. Anon也想玩双影奇境

题目大意

给定 T T T 组数据,每组有两个正整数 n , m n, m n,m

对每个 n , m n, m n,m,要求算出其二进制表示有多少位是相同的(如果长度不一样就补前导零)。

例如 n = 2 , m = 19 n = 2, m = 19 n=2,m=19,其二进制表示分别是 00010 , 10011 00010, 10011 00010,10011,有 3 3 3 位相同。

Solution

用短除法将 n , m n, m n,m 转化为二进制字符串,并补齐前导零后,直接遍历比较即可。

时间复杂度 O ( ∑ log ⁡ max ⁡ ( n , m ) ) O(\sum\log\max(\rm{n}, \rm{m})) O(logmax(n,m))

C++ Code

#include <bits/stdc++.h>using i64 = long long;
using u64 = unsigned long long;
using u32 = unsigned;
using i80 = __int128_t;
using u80 = unsigned __int128_t;
using f64 = double;
using f80 = long double;
using i16 = short;
using u16 = unsigned short;constexpr f64 pi = std::numbers::pi;std::mt19937 rng(std::chrono::steady_clock::now().time_since_epoch().count());void solve() {int n, m;std::cin >> n >> m;auto get = [&](int x) {std::string ans;for (int y = x; y > 0; y /= 2) {ans += char(y % 2 + '0');}return ans;};auto sn = get(n);auto sm = get(m);while (sn.size() < sm.size()) {sn += '0';}while (sm.size() < sn.size()) {sm += '0';}int N = sn.size();std::cout << std::ranges::count_if(std::views::iota(0, N), [&](int i) {return sn[i] == sm[i];}) << "\n";
}int main() {std::ios::sync_with_stdio(false);std::cin.tie(nullptr);std::cout << std::fixed << std::setprecision(12);int T = 1;std::cin >> T;while (T--) {solve();}return 0;
}

D. 诗寇蒂Skuld

题目大意

给定 n n n 朵花的信息 a i , l i , r i a_i, l_i, r_i ai,li,ri,分别表示第 i i i 朵花的 美丽值 以及 开花的区间 [ l i , r i ] [l_i, r_i] [li,ri]。再给定一个 m m m 表示你可以施展魔法的次数;每次施展魔法你可以做如下操作一次:

  • 选定一个下标 i i i,要么令 l i : = l i − 1 l_i := l_i - 1 li:=li1,要么令 r i : = r i + 1 r_i := r_i + 1 ri:=ri+1

现在规定某一天的美丽值 A A A 为** 所有盛开的花的美丽值之和**,求出最多使用 m m m 次魔法后的 max ⁡ ( A ) \max(A) max(A)

数据范围

  • 1 ≤ n ≤ 100 1 \leq n \leq 100 1n100
  • 0 ≤ m ≤ 2025 0 \leq m \leq 2025 0m2025
  • 1 ≤ a i , l i , r i ≤ 1 0 9 1 \leq a_i, l_i, r_i \leq 10^9 1ai,li,ri109

Solution

首先给出结论,这种题目的 某一天 一定可以在某个端点 l i l_i li r i r_i ri 处取到。

假设我们是在 非端点处 d d d 求得了 max ⁡ ( A ) \max(A) max(A),那么一定存在一些 i i i 使得 d ∈ ( l i , r i ) d \in (l_i, r_i) d(li,ri),否则去到区间并 ⋃ i = 1 n [ l i , r i ] \bigcup\limits_{i = 1}^{n} [l_i, r_i] i=1n[li,ri] 都没有覆盖的地方,一定不会最优。此时对于那些不包含 d d d 的区间 [ l j , r j ] [l_j, r_j] [lj,rj],一定有 d < l j d < l_j d<lj d > r j d > r_j d>rj(因为 d d d 一定不在端点)。

设对于当前 d d d

  • 包含 d d d 的区间下标集合为 C C C
  • 左边有 c l c_l cl 个区间可以通过魔法改变右端点到达 d d d,操作 s l s_l sl 次;
  • 右边有 c r c_r cr 个区间可以通过魔法改变左端点到达 d d d,操作 s r s_r sr 次。

下面说明我们可以将 d d d 移到端点而保持答案不变甚至更优。

  • c l < c r c_l < c_r cl<cr,那我们可以找到一个 i ∈ C i \in C iC,使得 r i = min ⁡ k ∈ C r k r_i = \min\limits_{k \in C}r_k ri=kCminrk,此时将 d d d 右移到 r i r_i ri,那么 s l : = s l + c l , s r : = s r − c r , s_l := s_l + c_l, \\ s_r := s_r - c_r, sl:=sl+cl,sr:=srcr, 这样一来总的操作次数 s = s l + s r s = s_l + s_r s=sl+sr 就变小了,而且美丽值不变;
  • c l > c r c_l > c_r cl>cr,那我们可以找到一个 i ∈ C i \in C iC,使得 l i = max ⁡ k ∈ C l k l_i = \max\limits_{k \in C}l_k li=kCmaxlk,此时将 d d d 左移到 l i l_i li,那么 s l : = s l − c l , s r : = s r + c r , s_l := s_l - c_l, \\ s_r := s_r + c_r, sl:=slcl,sr:=sr+cr, 这样一来总的操作次数 s = s l + s r s = s_l + s_r s=sl+sr 就变小了,而且美丽值不变;
  • c l = c r c_l = c_r cl=cr,那我们随便往上述的 l i l_i li r i r_i ri 移,总操作次数 s s s 不变。

综上,在端点处一定可以取到 max ⁡ ( A ) \max(A) max(A)

下设 c o s t i ( d ) cost_i(d) costi(d) 函数( i ∈ [ 1 , n ] i \in [1, n] i[1,n]):

c o s t i ( d ) = { l i − d , d < l i , 0 , d ∈ [ l i , r i ] d − r i , d > r i . cost_i(d) = \begin{cases} l_i - d,& d < l_i, \\ 0,& d \in [l_i, r_i] \\ d - r_i,& d > r_i. \end{cases} costi(d)= lid,0,dri,d<li,d[li,ri]d>ri.

对于当前的 d d d,可以把 c o s t i ( d ) cost_i(d) costi(d) 看成物品体积,把 a i a_i ai 看成物品价值,这样就变成了背包容量为 m m m 的一个 01 01 01 背包问题了。

时间复杂度 O ( n 2 m ) O(\rm{n}^2\rm{m}) O(n2m)

C++ Code

#include <bits/stdc++.h>using i64 = long long;
using u64 = unsigned long long;
using u32 = unsigned;
using i80 = __int128_t;
using u80 = unsigned __int128_t;
using f64 = double;
using f80 = long double;
using i16 = short;
using u16 = unsigned short;constexpr f64 pi = std::numbers::pi;template<class T, size_t L>
std::istream &operator>>(std::istream &is, std::array<T, L> &a) {for (auto &x: a) {is >> x;}return is;
}
template<class T>
std::istream &operator>>(std::istream &is, std::vector<T> &v) {for (auto &x: v) {is >> x;}return is;
}int main() {std::ios::sync_with_stdio(false);std::cin.tie(nullptr);int n, m;std::cin >> n >> m;std::vector<std::array<int, 3>> flower(n);std::cin >> flower;std::vector<int> days;for (const auto &[a, l, r]: flower) {days.push_back(l);days.push_back(r);}std::ranges::sort(days);days.erase(std::unique(days.begin(), days.end()), days.end());i64 ans = 0;for (int d: days) {i64 sum = 0;std::vector<std::pair<int, int>> obj;for (const auto &[a, l, r]: flower) {if (d < l) {obj.emplace_back(l - d, a);} else if (d > r) {obj.emplace_back(d - r, a);} else {sum += a;}}std::vector<i64> dp(m + 1);for (const auto &[v, w]: obj) {for (int s = m; s >= v; s--) {dp[s] = std::max(dp[s], dp[s - v] + w);}}ans = std::max(ans, sum + dp[m]);}std::cout << ans << "\n";return 0;
}

E. 乌尔德+Urd

题目大意

给定 T T T 组数据,每组给定三个正整数 n , m , p n, m, p n,m,p

设有无穷多项的斐波那契数列 f 1 = 1 , f 2 = 1 , f 3 = 2 , ⋯ f_1 = 1, f_2 = 1, f_3 = 2, \cdots f1=1,f2=1,f3=2,

对每个 n , m , p n, m, p n,m,p,求 ∑ i = 1 n [ m ∣ i ] ⋅ f i . \sum\limits_{i = 1}^{n}[m \mid i] \cdot f_i. i=1n[mi]fi.

其中 m ∣ i m \mid i mi 表示 m m m 可以整除 i i i,例如 2 ∣ 4 2 \mid 4 24 f i f_i fi 表示斐波那契数列的第 i i i 项。

数据范围

  • 1 ≤ T ≤ 1 0 5 1 \leq T \leq 10^5 1T105
  • 1 ≤ n , m ≤ 1 0 18 1 \leq n, m \leq 10^{18} 1n,m1018
  • 1 ≤ p ≤ 1 0 9 1 \leq p \leq 10^9 1p109

Solution

其实在斐波那契这里看见这么大的数据范围,就应该立即想到矩阵快速幂了。

我们特别规定 f 0 = 0 f_0 = 0 f0=0。考虑一个二维向量 F n = [ f n , f n + 1 ] F_n = [f_n, f_{n + 1}] Fn=[fn,fn+1],以及一个转移矩阵

A = [ 0 1 1 1 ] , A = \begin{bmatrix} 0 & 1 \\ 1 & 1 \end{bmatrix}, A=[0111],

这样一来就有 F n + 1 = F n × A F_{n + 1} = F_n \times A Fn+1=Fn×A,根据矩阵的结合律,有 F n = F 0 × A n F_n = F_0 \times A^n Fn=F0×An

那么求和式可以化简为( F n [ 0 ] = f n F_n[0] = f _n Fn[0]=fn

∑ i = 1 n [ m ∣ i ] ⋅ f i = ∑ i = 1 ⌊ n m ⌋ f i ⋅ m = ∑ i = 1 ⌊ n m ⌋ F i ⋅ m [ 0 ] = ∑ i = 1 ⌊ n m ⌋ ( F 0 × A i ⋅ m ) [ 0 ] = ( F 0 ∑ i = 1 ⌊ n m ⌋ ( A m ) i ) [ 0 ] = ( [ 0 , 1 ] ∑ i = 1 ⌊ n m ⌋ ( A m ) i ) [ 0 ] = ∑ i = 1 ⌊ n m ⌋ ( B i ) [ 1 ] [ 0 ] . \begin{align*} \sum\limits_{i = 1}^{n}[m \mid i] \cdot f_i &= \sum\limits_{i = 1}^{\lfloor \frac{n}{m} \rfloor}f_{i \cdot m} \\ &= \sum\limits_{i = 1}^{\lfloor \frac{n}{m} \rfloor}F_{i \cdot m}[0] \\ &= \sum\limits_{i = 1}^{\lfloor \frac{n}{m} \rfloor}(F_0 \times A^{i \cdot m})[0] \\ &= (F_0\sum\limits_{i = 1}^{\lfloor \frac{n}{m} \rfloor}(A^m)^i)[0] \\ &= ([0, 1]\sum\limits_{i = 1}^{\lfloor \frac{n}{m} \rfloor}(A^m)^i)[0] \\ &= \sum\limits_{i = 1}^{\lfloor \frac{n}{m} \rfloor} (B^i)[1][0]. \end{align*} i=1n[mi]fi=i=1mnfim=i=1mnFim[0]=i=1mn(F0×Aim)[0]=(F0i=1mn(Am)i)[0]=([0,1]i=1mn(Am)i)[0]=i=1mn(Bi)[1][0].

其中 B = A m B = A^m B=Am B [ 1 ] [ 0 ] B[1][0] B[1][0] 表示 B B B 这个二维矩阵第 1 1 1 行第 0 0 0 列的元素(下标从 0 0 0 开始)。

那么我们其实可以求出 ∑ i = 1 ⌊ n m ⌋ B i \sum\limits_{i = 1}^{\lfloor \frac{n}{m} \rfloor}B^i i=1mnBi 后,再取其第 1 1 1 行第 0 0 0 列的元素。而考虑单位阵 E = [ 1 0 0 1 ] E = \begin{bmatrix} 1 & 0 \\ 0 & 1 \end{bmatrix} E=[1001] 的左下角是 0 0 0,所以我们可以求 E + ∑ i = 1 ⌊ n m ⌋ B i = ∑ i = 0 ⌊ n m ⌋ B i E + \sum\limits_{i = 1}^{\lfloor \frac{n}{m} \rfloor}B^i = \sum\limits_{i = 0}^{\lfloor \frac{n}{m} \rfloor}B^i E+i=1mnBi=i=0mnBi

下设 N = ⌊ n m ⌋ N = \lfloor \frac{n}{m} \rfloor N=mn,我们考虑分治求解 ∑ i = 0 N B i \sum\limits_{i = 0}^{N}B^i i=0NBi

  • N = 0 N = 0 N=0,直接返回 E E E
  • N N N 为奇数,那么式子可以拆成长度相同的两部分,分别是 E + A + A 2 + ⋯ + A ⌊ N 2 ⌋ , A ⌊ N 2 ⌋ + 1 + A ⌊ N 2 ⌋ + 2 + ⋯ + A N . E + A + A^2 + \cdots + A^{\lfloor \frac{N}{2} \rfloor}, \\ A^{\lfloor \frac{N}{2} \rfloor + 1} + A^{\lfloor \frac{N}{2} \rfloor +2} + \cdots + A^N. E+A+A2++A2N,A2N+1+A2N+2++AN. 而把下面提一个 A ⌊ N 2 ⌋ + 1 A^{\lfloor \frac{N}{2} \rfloor + 1} A2N+1 就可以得到上面,所以直接算前一半,最后乘以 ( E + A ⌊ N 2 ⌋ + 1 ) (E + A^{\lfloor \frac{N}{2} \rfloor + 1}) (E+A2N+1) 即可。
  • N N N 为偶数,先把 E E E 去掉,再对后面的式子提一个 A A A,就可以得到 E + A ( E + A + A 2 + ⋯ + A N − 1 ) , E + A(E + A + A^2 + \cdots + A^{N - 1}), E+A(E+A+A2++AN1), 后面的 ( E + A + A 2 + ⋯ + A N − 1 ) (E + A + A^2 + \cdots + A^{N - 1}) (E+A+A2++AN1) 就是 N − 1 N - 1 N1 为奇数的情况。

时间复杂度 O ( ∑ ( log ⁡ m + log ⁡ ⌊ n m ⌋ ) ) = O ( ∑ log ⁡ n ) O(\sum(\log m + \log \lfloor \frac{n}{m} \rfloor)) = O(\sum\log n) O((logm+logmn⌋))=O(logn)

  • 其中 2 × 2 2 \times 2 2×2 矩阵的常数基本可以忽略。

C++ Code

#include <bits/stdc++.h>using i64 = long long;
using u64 = unsigned long long;
using u32 = unsigned;
using i80 = __int128_t;
using u80 = unsigned __int128_t;
using f64 = double;
using f80 = long double;
using i16 = short;
using u16 = unsigned short;constexpr f64 pi = std::numbers::pi;std::mt19937 rng(std::chrono::steady_clock::now().time_since_epoch().count());template<int P>
struct MInt {int x;constexpr MInt() : x{} {}constexpr MInt(i64 x) : x{norm(x % getMod())} {}static int Mod;constexpr static int getMod() {if (P > 0) {return P;} else {return Mod;}}constexpr static void setMod(int Mod_) {Mod = Mod_;}constexpr int norm(int x) const {if (x < 0) {x += getMod();}if (x >= getMod()) {x -= getMod();}return x;}constexpr int val() const {return x;}explicit constexpr operator int() const {return x;}constexpr MInt operator-() const {MInt res;res.x = norm(getMod() - x);return res;}constexpr MInt inv() const {assert(x != 0);return power(*this, getMod() - 2);}constexpr MInt &operator*=(MInt rhs) & {x = 1LL * x * rhs.x % getMod();return *this;}constexpr MInt &operator+=(MInt rhs) & {x = norm(x + rhs.x);return *this;}constexpr MInt &operator-=(MInt rhs) & {x = norm(x - rhs.x);return *this;}constexpr MInt &operator/=(MInt rhs) & {return *this *= rhs.inv();}friend constexpr MInt operator*(MInt lhs, MInt rhs) {MInt res = lhs;res *= rhs;return res;}friend constexpr MInt operator+(MInt lhs, MInt rhs) {MInt res = lhs;res += rhs;return res;}friend constexpr MInt operator-(MInt lhs, MInt rhs) {MInt res = lhs;res -= rhs;return res;}friend constexpr MInt operator/(MInt lhs, MInt rhs) {MInt res = lhs;res /= rhs;return res;}friend constexpr std::istream &operator>>(std::istream &is, MInt &a) {i64 v;is >> v;a = MInt(v);return is;}friend constexpr std::ostream &operator<<(std::ostream &os, const MInt &a) {return os << a.val();}friend constexpr bool operator==(MInt lhs, MInt rhs) {return lhs.val() == rhs.val();}friend constexpr bool operator!=(MInt lhs, MInt rhs) {return lhs.val() != rhs.val();}
};template<>
int MInt<0>::Mod = 998244353;template<int V, int P>
constexpr MInt<P> CInv = MInt<P>(V).inv();constexpr int P = 0;
using Z = MInt<P>;template<class T>
T power(T a, i64 b) {T res;res.unit(a.n);for ( ; b; b /= 2, a *= a) {if (b & 1) {res *= a;}}return res;
}
template<class T>
struct Matrix {int n, m;std::vector<std::vector<T>> g;Matrix() {}Matrix(int _n, int _m) {init(_n, _m);}Matrix(int _n) {init(_n);}template<class T2>Matrix(std::vector<std::vector<T2>> _g) {init(_g);}void init(int _n, int _m) {n = _n, m = _m;g.resize(n);for (int i = 0; i < n; i += 1) {g[i].resize(m);}}void init(int _n) {init(_n, _n);}void unit(int _n) {init(_n, _n);for (int i = 0; i < n; i += 1) {g[i][i] = 1;}}template<class T2>void init(std::vector<std::vector<T2>> _g) {init(_g.size(), _g[0].size());for (int i = 0; i < n; i += 1) {for (int j = 0; j < m; j += 1) {g[i][j] = T(_g[i][j]);}}}std::vector<T> &operator[](int i) { return g[i];}void fill(const T v) {for (int i = 0; i < n; i += 1) {g[i].assign(m, v);}}// 0:逆时针,1:顺时针void rotate(int d, int x1, int y1, int x2, int y2) {assert(d == 0 or d == 1);Matrix<T> G(n, m);if (x2 - x1 == n and y2 - y1 == m) {G.init(m, n);}if (d == 0) {for (int i = 0; i < n; i += 1) {for (int j = 0; j < m; j += 1) {if (i >= x1 and i < x2 and j >= y1 and j < y2) {G[x2 - (j - y1) - 1][y1 + (i - x1)] = g[i][j];} else {G[i][j] = g[i][j];}}}} else {for (int i = 0; i < n; i += 1) {for (int j = 0; j < m; j += 1) {if (i >= x1 and i < x2 and j >= y1 and j < y2) {G[x1 + (j - y1)][y2 - (i - x1) - 1] = g[i][j];} else {G[i][j] = g[i][j];}}}}*this = G;}void rotate(int d) {rotate(d, 0, 0, n, m);}// 0:上下翻转,1:左右翻转void flip(int d, int x1, int y1, int x2, int y2) {assert(d == 0 or d == 1);Matrix<T> G(n, m);if (d == 0) {for (int i = 0; i < n; i += 1) {for (int j = 0; j < m; j += 1) {if (i >= x1 and i < x2 and j >= y1 and j < y2) {G[(x1 + x2) - i - 1][j] = g[i][j];} else {G[i][j] = g[i][j];}}}} else {for (int i = 0; i < n; i += 1) {for (int j = 0; j < m; j += 1) {if (i >= x1 and i < x2 and j >= y1 and j < y2) {G[i][(y1 + y2) - j - 1] = g[i][j];} else {G[i][j] = g[i][j];}}}}*this = G;}void flip(int d) {flip(d, 0, 0, n, m);}Matrix<T> transpose() {Matrix<T> res(m, n);for (int i = 0; i < n; i += 1) {for (int j = 0; j < m; j += 1) {res[j][i] = g[i][j];}}return res;}template<class T2>Matrix<T> &operator+=(Matrix<T2> A) & {assert(n == A.n and m == A.m);for (int i = 0; i < n; i += 1) {for (int j = 0; j < m; j += 1) {g[i][j] += T(A[i][j]);}}return *this;}template<class T2>friend Matrix<T> operator+(Matrix<T> A, Matrix<T2> B) {Matrix<T> res = A;res += B;return res;}template<class T2>Matrix<T> &operator-=(Matrix<T2> A) & {assert(n == A.n and m == A.m);for (int i = 0; i < n; i += 1) {for (int j = 0; j < m; j += 1) {g[i][j] -= T(A[i][j]);}}return *this;}template<class T2>friend Matrix<T> operator-(Matrix<T> A, Matrix<T2> B) {Matrix<T> res = A;res -= B;return res;}template<class T2>Matrix<T> &operator*=(Matrix<T2> A) & {assert(m == A.n);Matrix<T> res(n, A.m);for (int i = 0; i < n; i += 1) {for (int j = 0; j < A.m; j += 1) {for (int k = 0; k < m; k += 1) {res[i][j] += g[i][k] * T(A[k][j]);}}}return *this = res;}template<class T2>friend Matrix<T> operator*(Matrix<T> A, Matrix<T2> B) {Matrix<T> res = A;res *= B;return res;}friend std::istream &operator>>(std::istream &is, Matrix<T> &A) {for (int i = 0; i < A.n; i += 1) {for (int j = 0; j < A.m; j += 1) {is >> A[i][j];}}return is;}friend std::ostream &operator<<(std::ostream &os, Matrix<T> &A) {for (int i = 0; i < A.n; i += 1) {for (int j = 0; j < A.m; j += 1) {os << A[i][j] << " \n"[j + 1 == A.m];}}return os;}friend bool operator==(Matrix<T> A, Matrix<T> B) {if (A.n != B.n) {return false;} else if (A.m != B.m) {return false;}for (int i = 0; i < A.n; i += 1) {for (int j = 0; j < A.m; j += 1) {if (A[i][j] != B[i][j]) {return false;}}}return true;}friend bool operator!=(Matrix<T> A, Matrix<T> B) {if (A.n != B.n) {return true;} else if (A.m != B.m) {return true;}for (int i = 0; i < A.n; i += 1) {for (int j = 0; j < A.m; j += 1) {if (A[i][j] != B[i][j]) {return true;}}}return false;}friend bool operator<(Matrix<T> A, Matrix<T> B) {if (A.n != B.n) {return A.n < B.n;} else if (A.m != B.m) {return A.m < B.m;}for (int i = 0; i < A.n; i += 1) {for (int j = 0; j < A.m; j += 1) {if (A[i][j] != B[i][j]) {return A[i][j] < B[i][j];}}}return false;}friend bool operator>(Matrix<T> A, Matrix<T> B) {if (A.n != B.n) {return A.n > B.n;} else if (A.m != B.m) {return A.m > B.m;}for (int i = 0; i < A.n; i += 1) {for (int j = 0; j < A.m; j += 1) {if (A[i][j] != B[i][j]) {return A[i][j] > B[i][j];}}}return false;}
};void solve() {i64 n, m, p;std::cin >> n >> m >> p;if (p == 1) {std::cout << 0 << "\n";return;}Z::setMod(p);Matrix<Z> E(std::vector<std::vector<Z>>{{1, 0},{0, 1}});Matrix<Z> A(std::vector<std::vector<Z>>{{0, 1},{1, 1}});A = power(A, m);auto dfs = [&](auto &&self, i64 n) -> Matrix<Z> {if (n == 0) {return E;}return (n & 1) ? (E + power(A, n / 2 + 1)) * self(self, n / 2): (E + A * self(self, n - 1));};auto ans = dfs(dfs, n / m);std::cout << ans[1][0] << "\n";
}int main() {std::ios::sync_with_stdio(false);std::cin.tie(nullptr);std::cout << std::fixed << std::setprecision(12);int T = 1;std::cin >> T;while (T--) {solve();}return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/73089.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

APScheduler - 用户指南

本文翻译整理自&#xff1a;https://apscheduler.readthedocs.io/en/3.x/userguide.html 文章目录 一、安装 APScheduler二、代码示例三、基本概念四、选择合适的 scheduler, job store(s), executor(s) and trigger(s)五、配置调度器方法 1:方法 2:方法 3: 六、启动调度器七、…

vue3:十一、主页面布局(优化页面跳转方式)

:router"true" 一、参考文章 vue3:十一、主页面布局(实现基本左侧菜单右侧内容效果)-CSDN博客 参考上述文章可知&#xff0c;页面跳转是通过在js中定义的菜单中携带的path&#xff0c;然后通过菜单的点击事件完成的跳转&#xff0c;现在可以进行优化&#xff0c;直…

每日一题--C与C++的差别

C与C的差别 1. 编程范式 C 纯 过程式编程语言&#xff0c;强调函数和结构化编程。 代码通过函数和顺序步骤组织&#xff0c;适合底层系统开发。 C 支持 多范式编程&#xff1a; 过程式编程 面向对象编程&#xff08;OOP&#xff09;&#xff08;类、继承、多态&#xff09; …

Etcd 服务搭建

&#x1f4a2;欢迎来到张胤尘的开源技术站 &#x1f4a5;开源如江河&#xff0c;汇聚众志成。代码似星辰&#xff0c;照亮行征程。开源精神长&#xff0c;传承永不忘。携手共前行&#xff0c;未来更辉煌&#x1f4a5; 文章目录 Etcd 服务搭建预编译的二进制文件安装下载 etcd 的…

玩转C#函数:参数、返回值与游戏中的攻击逻辑封装

Langchain系列文章目录 01-玩转LangChain&#xff1a;从模型调用到Prompt模板与输出解析的完整指南 02-玩转 LangChain Memory 模块&#xff1a;四种记忆类型详解及应用场景全覆盖 03-全面掌握 LangChain&#xff1a;从核心链条构建到动态任务分配的实战指南 04-玩转 LangChai…

WebRTC建立Description的通信的实际的原理

一、正确流程的核心逻辑 // 发送端正确代码示例 const senderPC new RTCPeerConnection();// 生成Offer时立即开始收集候选 ✅ senderPC.createOffer().then(offer > {await senderPC.setLocalDescription(offer); // 触发icecandidate事件sendToReceiver(offer); });// …

EmbodiedSAM:在线实时3D实例分割,利用视觉基础模型实现高效场景理解

2025-02-12&#xff0c;由清华大学和南洋理工大学的研究团队开发 一种名为 EmbodiedSAM&#xff08;ESAM&#xff09;的在线3D实例分割框架。该框架利用2D视觉基础模型辅助实时3D场景理解&#xff0c;解决了高质量3D数据稀缺的难题&#xff0c;为机器人导航、操作等任务提供了高…

信创-人大金仓数据库创建

一. 官文 资源下载地址 https://download.kingbase.com.cn/xzzx/index.htm 下载安装文件 下载授权文件 产品文档地址&#xff1a;https://help.kingbase.com.cn/v8/index.html 二. 概念 2.1 体系结构 ‌ 实例结构 ‌&#xff1a;由数据库文件和 KingbaseES 实例组成。数据…

C++第三种异质集合 std::any方式实现

#include <type_traits> #include <any> #include <functional> #include <iomanip> #include <iostream> #include <typeindex> #include <typeinfo> #include <unordered_map> #include <vector> //any是编译期的异质…

Springboot实现使用断点续传优化同步导入Excel

springboot实现使用断点续传优化同步导入Excel 需求前言断点续传前端实现后端实现完结撒花&#xff0c;如有需要收藏的看官&#xff0c;顺便也用发财的小手点点赞哈&#xff0c;如有错漏&#xff0c;也欢迎各位在评论区评论&#xff01; 需求前言 在跨境电商系统中&#xff0c…

mysql 对json的处理?

MySQL从5.7版本开始支持JSON数据类型&#xff0c;并提供了多种函数来查询和处理JSON数据。以下是一些基本的操作和函数&#xff1a; 创建包含JSON列的表&#xff1a; 可以直接在表定义中指定某列为JSON类型。 CREATE TABLE my_table (id INT NOT NULL AUTO_INCREMENT,data JSON…

Nexus L2 L3基本配置

接口基本配置 N7K上所有端口默认处于shutdown状态; N5K上所有端口默认处于no shutdown状态(所有端口都是switchport) 默认所有接口都是三层route模式, 只有当线卡不支持三层的时候, 接口才会处于二层switchport模式 show run all | in “system default” 创建SVI口需要提前打…

HCIA-AI人工智能笔记3:数据预处理

统讲解数据预处理的核心技术体系&#xff0c;通过Python/Pandas与华为MindSpore双视角代码演示&#xff0c;结合特征工程优化实验&#xff0c;深入解析数据清洗、标准化、增强等关键环节。 一、数据预处理技术全景图 graph TD A[原始数据] --> B{数据清洗} B --> B1[缺…

G-Star 校园开发者计划·黑科大|开源第一课之 Git 入门

万事开源先修 Git。Git 是当下主流的分布式版本控制工具&#xff0c;在软件开发、文档管理等方面用处极大。它能自动记录文件改动&#xff0c;简化合并流程&#xff0c;还特别适合多人协作开发。学会 Git&#xff0c;就相当于掌握了一把通往开源世界的钥匙&#xff0c;以后参与…

MySQL错误 “duplicate entry ‘1‘ for key ‘PRIMARY‘“ 解决方案

文章目录 1. 错误原因分析2. 快速解决方法场景1:手动插入重复值场景2:自增主键冲突场景3:批量插入冲突3. 长期预防策略4. 高级排查技巧该错误通常由主键冲突引起,表示尝试插入或更新的主键值已存在于表中。以下是分步排查和解决方法: 1. 错误原因分析 主键唯一性约束:表…

WEB攻防-PHP反序列化-字符串逃逸

目录 前置知识 字符串逃逸-减少 字符串逃逸-增多 前置知识 1.PHP 在反序列化时&#xff0c;语法是以 ; 作为字段的分隔&#xff0c;以 } 作为结尾&#xff0c;在结束符}之后的任何内容不会影响反序列化的后的结果 class people{ public $namelili; public $age20; } var_du…

把生产队的大模型Grok 3 beta用来实现字帖打磨

第一个版本&#xff0c;就是简单的田字格&#xff0c;Grok 3 beta 思考了15s就得到了html前端代码&#xff0c;javascript; 然而还不完美&#xff1b; 第二个版本&#xff0c;进一步&#xff0c;通过pinyin项目给汉字加上注音&#xff0c;米字格和四线格&#xff1b;&#xff…

windows+ragflow+deepseek实战之一excel表查询

ragflows平台部署参考文章 Win10系统Docker+DeepSeek+ragflow搭建本地知识库 ragflow通过python实现参考这篇文章 ragflow通过python实现 文章目录 背景效果1、准备数据2、创建知识库3、上传数据并解析4、新建聊天助理5、测试会话背景 前面已经基于Win10系统Docker+DeepSeek+…

OpenCV图像处理基础2

接着上一篇OpenCV图像处理基础1继续说。 图像阈值处理 1、简单阈值处理 ret, thresholded_image = cv2.threshold(image, thresh, maxval, cv2.THRESH_BINARY)thresh 是阈值,maxval 是最大值。 2、自适应阈值处理 thresholded_image = cv2.adaptiveThreshold(image, maxv…

go安装lazydocker

安装 先安装go环境 https://blog.csdn.net/Yqha1/article/details/146430281?fromshareblogdetail&sharetypeblogdetail&sharerId146430281&sharereferPC&sharesourceYqha1&sharefromfrom_link 安装lazydocker go install github.com/jesseduffield/laz…