[bzoj2326][HNOI2011]数学作业
本题是一个典型的使用矩阵优化的题。
本题的特殊之处在于:矩阵是会变化的,而不是固定的。
所以我们要分阶段搞,而不是一下子搞。
容易得出:
f[i] = f[i-1] * 10 ^ k + i;
其中k由i决定。
变形一下原式:
f[i] = f[i-1] * 10 ^ k + (i-1) + 1;
容易构建矩阵:
\[\begin{equation}
\left[
\begin{array}{ccc}
f[i] & i-1 & 1
\end{array}
\right]
\end{equation}
\]
和变换矩阵:
\[\begin{equation}
\left[
\begin{array}{ccc}
10^k & 0 & 0 \\
1 & 1 & 0 \\
1 & 1 & 1
\end{array}
\right]
\end{equation}
\]
套用模板即可。
下面是代码。
#include <bits/stdc++.h>
using namespace std;
long long n, m;
#define ll long long
struct M {
ll v[4][4];
M() {
memset(v, 0, sizeof(v));
}
friend void print(M a) {
for(int i = 1; i <= 3; i++) {
for(int j = 1; j <= 3; j++)
cout << a.v[i][j] << ' ';
cout << endl;
}
}
friend M operator * (M a, M b) {
M ans;
for(int i = 1; i <= 3; i++) {
for(int j = 1; j <= 3; j++) {
for(int k = 1; k <= 3; k++) {
ans.v[i][j] = (ans.v[i][j] % m + (a.v[i][k]%m * b.v[k][j] % m)%m) % m;
}
}
}
return ans;
}
friend M operator ^ (M a, ll b) {
M ans;
for(int i = 1; i <= 3; i++) ans.v[i][i] = 1;
for(ll i = b; i; i >>= 1, a = a * a) {
if(i & 1) ans = ans * a;
}
return ans;
}
}a, b;
ll pow(ll a, ll b) {
int ans = 1;
for(int i = b; i; i >>= 1, a = a*a)
if(i &1) ans = ans*a;
return ans;
}
int main() {
scanf("%lld %lld", &n, &m);
a.v[1][1] = a.v[1][2] = 0;
a.v[1][3] = 1;
ll c = 10;
ll d = 1;
ll u = 0;
b.v[1][1] = pow(10, d);
b.v[2][1] =b.v[2][2]=b.v[3][1] = b.v[3][2]=b.v[3][3] = 1;
while(c-1 < n) {
a = a * (b ^ (pow(10, d) - u-1));
u = pow(10, d)-1;
d++;
c*=10;
b.v[1][1] = (b.v[1][1] * 10)%m;
}
b = b^(n-u);
a = a*b;
printf("%lld\n", a.v[1][1]);
return 0;
}
注:代码在bzoj上可以ac,但是在洛谷上不保证ac。