20200617 SCOI模拟T2(高精度)(矩阵快速幂)(数学问题)

T2 P4461 [CQOI2018]九连环

思路:
先推式子
发现对于 i 连环,必定先取下第 i
11 … … 1 − > 01 … … 1 11……1->01……1 111>011
考虑过程
111 … … 1 − > 110 … … 0 − > 010 … … 0 − > 011 … … 1 111……1\\ ->110……0\\ ->010……0\\ ->011……1 1111>1100>0100>0111
f [ i ] f[i] f[i]i 连环全部取下所用步数
有转移方程
f [ i ] = f [ i − 1 ] + 2 × f [ i − 2 ] + 1 f[i]=f[i-1]+2\times f[i-2]+1 f[i]=f[i1]+2×f[i2]+1
递推求通项
f [ i ] = ⌊ 2 i + 1 3 ⌋ f[i]=\lfloor \frac{2^{i+1}}{3} \rfloor f[i]=32i+1
可以矩阵快速幂
于是就……A了
一看数据范围,发现不对
需要高精
黑科技:压位高精
就是用一位数组存下多位十进制
一般对 1 e 9 1e9 1e9 取模(相乘不会爆 longlong

代码:

#include <bits/stdc++.h>
using namespace std;
#define in Read()
#define LL long long

inline char ch() {
  static char buf[1 << 21], *p1 = buf, *p2 = buf;
  return p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 1 << 21, stdin), p1 == p2)
             ? EOF
             : *p1++;
}

inline int in {
  int s = 0, f = 1;
  char x;
  for (x = ch(); x < '0' || x > '9'; x = ch())
    if (x == '-') f = -1;
  for (; x >= '0' && x <= '9'; x = ch()) s = (s * 10) + (x & 15);
  return f == 1 ? s : -s;
}

const int A = 1e5 + 5;
const LL mod = 1e9;
int m, n;
struct S {
  int a[A], len;
  S() { memset(a, 0, sizeof(a)); }
  inline S friend operator*(const S u, const S v) {
    S w;
    LL now = 0;
    for (int i = 1; i <= u.len; i++) {
      now = 0;
      for (int j = 1; j <= v.len; j++) {
        now += 1ll*u.a[i] * v.a[j] + 1ll*w.a[i + j - 1];
        w.a[i + j - 1] = now % mod;
        now /= mod;
      }
      if (now) w.a[i + v.len] = now;
    }
    w.len = u.len + v.len - 1;
    if (w.a[u.len + v.len]) w.len++;
    return w;
  }
  inline S friend operator/(const S u, LL v) {
    S w;
    LL now = 0;
    for (int i = u.len; i; i--) {
      now = 1ll*now * mod + 1ll*u.a[i];
      w.a[i] = 1ll*now / v;
      now %= v;
    }
    w.len = u.len;
    if (!w.a[u.len]) w.len--;
    return w;
  }
} u, v;

inline void print(S u) {
  S x = u;
  printf("%d", x.a[x.len]);
  for (int i = x.len - 1; i; i--) {
    for (int j = mod / 10; j; j /= 10) {
      printf("%d", x.a[i] / j);
      x.a[i] %= j;
    }
  }
  printf("\n");
  return;
}

inline S power(S u, LL c) {
  v.a[1] = 1, v.len = 1;
  while (c) {
    if (c & 1) v = v * u;
    u = u * u;
    c >>= 1;
  }
  return v;
}

signed main() {
  m = in;
  while (m--) {
    n = in;
    n++;
    u.a[1] = 2, u.len = 1;
    u = power(u, n);
    u = u / 3;
    print(u);
  }
  return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值