HDU 6145 Arithmetic of Bomb II or Aizu 2789 Compressed Formula 表達式展開求值 矩陣快速冪

鏈接

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的常量ϵ ,面對後面加進來的字符,有如下的矩陣運算(要詳細解釋也很麻煩,在紙上推演下很容易就懂了):

  1. 式子後面添加一個數字d

    相當於

    spdpd2ϵT = spdpd2ϵT * 1000010d000100001

    即s,pd2和ϵ 保持不變,當前單項式的最後一個係數進位並加上新的數字

  2. 式子後面添加一個加號或減號

    相當於

    spdpd2ϵT = spdpd2ϵT * 11000000000±10001

    ϵ 保持不變,s加上當前單項式pd置爲0,pd2變爲±對應的±1

  3. 式子後面添加一個乘號

    相當於

    spdpd2ϵT = spdpd2ϵ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);
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章