鏈接
http://acm.hdu.edu.cn/showproblem.php?pid=6145
http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=2789
題意
給n個表達式,每個表達式重複k次,問這個表達式的值是多少
思路
一開始自己打算分類討論的,結果不知道哪裏寫醜了……寫了200+還是wa,後來去問snowy_smile大神,他告訴我這題和百度之星2017複賽02一樣,於是自己去best coder看了看杜教的代碼,結合icpc camp的題解知道了做法(每次就你廢話最多……)
考慮維護當前表達式前面多項式的和s,當前多項式的乘積pd,以及當前多項式除去最後一個因子的乘積pd2,爲了方便再加一個值爲1的常量
式子後面添加一個數字d
相當於
⎡⎣⎢⎢⎢spdpd2ϵ⎤⎦⎥⎥⎥T =⎡⎣⎢⎢⎢⎢s′pd′pd2′ϵ′⎤⎦⎥⎥⎥⎥T *⎡⎣⎢⎢⎢1000010d000100001⎤⎦⎥⎥⎥ 即s,pd2和
ϵ 保持不變,當前單項式的最後一個係數進位並加上新的數字式子後面添加一個加號或減號
相當於
⎡⎣⎢⎢⎢spdpd2ϵ⎤⎦⎥⎥⎥T =⎡⎣⎢⎢⎢⎢s′pd′pd2′ϵ′⎤⎦⎥⎥⎥⎥T *⎡⎣⎢⎢⎢11000000000±10001⎤⎦⎥⎥⎥ 即
ϵ 保持不變,s加上當前單項式pd置爲0,pd2變爲±對應的±1式子後面添加一個乘號
相當於
⎡⎣⎢⎢⎢spdpd2ϵ⎤⎦⎥⎥⎥T =⎡⎣⎢⎢⎢⎢s′pd′pd2′ϵ′⎤⎦⎥⎥⎥⎥T *⎡⎣⎢⎢⎢1000000001000001⎤⎦⎥⎥⎥ 即s,
ϵ 保持不變,pd置爲0(由於*後面跟着的一定是數字,所以pd在當前矩陣乘上情況1的矩陣後又會恢復正常),pd2變爲pd
根據輸入的字符不斷使用矩陣乘法,最後快速冪即可。
求答案的時候用[0,0,1,1]這個矩陣去求s和pd,兩者相加就是答案
代碼
aizu 2789的代碼,hdu 6145也是相同
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long LL;
const int N = 4;
const int MOD = 1e9 + 7;
typedef LL Mat[N][N];
int n, r;
char s[20];
Mat tmp, ret, ans;
void mul(Mat &a, Mat &b) {
for (int i = 0; i < N; ++i) for (int j = 0; j < N; ++j) {
tmp[i][j] = 0;
for (int k = 0; k < N; ++k) tmp[i][j] += a[i][k] * b[k][j];
}
for (int i = 0; i < N; ++i) for (int j = 0; j < N; ++j) a[i][j] = tmp[i][j] % MOD;
}
void Pow(Mat &a, int b) {
for (int i = 0; i < N; ++i) for (int j = 0; j < N; ++j) ret[i][j] = (i==j);
for (; b; b >>= 1) {
if (b&1) mul(ret, a);
mul(a, a);
}
for (int i = 0; i < N; ++i) for (int j = 0; j < N; ++j) a[i][j] = ret[i][j];
}
void solve() {
Mat pre, nxt;
for (int i = 0; i < N; ++i) for (int j = 0; j < N; ++j) pre[i][j] = (i==j);
for (int k = 0; s[k]; ++k) {
for (int i = 0; i < N; ++i) for (int j = 0; j < N; ++j) nxt[i][j] = 0;
nxt[0][0] = nxt[3][3] = 1;
if (s[k] == '+' || s[k] == '-') {
nxt[1][0] = 1; nxt[3][2] = s[k] == '+' ? 1 : MOD - 1;
}
else if ('0' <= s[k] && s[k] <= '9') {
nxt[1][1] = 10; nxt[2][2] = 1; nxt[2][1] = s[k] - '0';
}
else {
nxt[1][2] = 1;
}
mul(pre, nxt);
}
Pow(pre, r);
mul(ans, pre);
}
int main() {
scanf("%d", &n);
for (int i = 0; i < N; ++i) for (int j = 0; j < N; ++j) ans[i][j] = (i==j);
for (int i = 0; i < n; ++i) {
scanf("%d%s", &r, s);
solve();
}
LL s = (ans[2][0] + ans[3][0] + MOD) % MOD, pd = (ans[2][1] + ans[3][1] + MOD) % MOD;
printf("%lld\n", (s + pd) % MOD);
}