# 幂运算

$n$$n$$a$$a$ 相加我们当然不会写成一个循环，$n$$n$$a$$a$ 相乘我们自然要用幂运算。

## 幂运算裸题

PAT L1-012: 计算指数

### 过题代码

#include <iostream>
#include <cmath>
using namespace std;

int main() {
int n;
cin >> n;
cout << 2 << "^" << n << " = " << pow(2, n) << endl;
return 0;
}

# 快速幂运算

$\left(a×b\right)\mathrm{%}c=\left(a\mathrm{%}c×b\mathrm{%}c\right)\mathrm{%}c\phantom{\rule{0ex}{0ex}}\left(a+b\right)\mathrm{%}c=\left(a\mathrm{%}c+b\mathrm{%}c\right)\mathrm{%}c$

## 算法思想

${a}^{bc}=\left({a}^{b}{\right)}^{c}\phantom{\rule{0ex}{0ex}}{a}^{b+c}={a}^{b}×{a}^{c}$

${x}^{n}=\left\{\begin{array}{l}\left({x}^{\frac{n-1}{2}}{\right)}^{2}×x\phantom{\rule{1em}{0ex}}\left(n\mathrm{%}2=1\right)\\ \left({x}^{\frac{n}{2}}{\right)}^{2}\phantom{\rule{1em}{0ex}}\phantom{\rule{1em}{0ex}}\phantom{\rule{1em}{0ex}}\left(n\mathrm{%}2=0\right)\end{array}$

## 幂运算题改

### 题意

$n=18654203254124875$$n=18654203254124875$ 时求出${2}^{n}$$2^n$ 的结果，由于该结果非常大，所以只要求输出$mod\left({2}^{n},{10}^{9}+7\right)$$mod(2^n,10^9+7)$ 的值。

### 代码

#include <iostream>
using namespace std;

#define LL long long

const LL MOD = 1000000007;

LL mi(LL res, LL n) {
LL ans;
for(ans = 1; n != 0; n >>= 1) {
if(n % 2 == 1) {
ans = (ans * res) % MOD;
}
res = (res * res) % MOD;
//        cout << "ans = " << res << "^" << n / 2 << " * " << ans << endl << endl;
//        cout << "ans = " << ans << "    res = " << res << "    n = " << n << endl << endl;
}
return ans;
}

int main() {
LL n;
cin >> n;
cout << "2^" << n << " = " << mi(2, n) << endl;

return 0;
}

## 快速幂裸题

### 题目链接

POJ 1995: Raising Modulo Numbers

### 题意

$\left({A}_{1}^{{B}_{1}}+{A}_{2}^{{B}_{2}}+{A}_{3}^{{B}_{3}}+...+{A}_{H}^{{B}_{H}}\right)modM$

### 过题代码

#include <iostream>
using namespace std;

#define LL long long

LL mi(LL res, LL n, LL MOD) {
LL ans;
for(ans = 1; n != 0; n >>= 1) {
if(n % 2 == 1) {
ans = (ans * res) % MOD;
}
res = (res * res) % MOD;
}
return ans;
}

int main() {
ios::sync_with_stdio(false);
LL Z, M, N;
LL ans, a, b;

cin >> Z;
while(Z--) {
ans = 0;
cin >> M >> N;
for(int i = 0; i < N; ++i) {
cin >> a >> b;
ans = (ans + mi(a, b, M)) % M;
}
cout << ans << endl;
}

return 0;
}

# 简单dp

## 关于动态规划

dp 是动态规划的简称，动态规划大家第一次听大概是在上课的时候，老师教到递归求斐波那契数列时提到的动态规划记录状态的解法吧。动态规划什么原理什么性的，很多博客已经说得很清楚了，大多是复制粘贴，这里不再赘述，想要详细了解的，请点传送门

$dp\left(n\right)=\left\{\begin{array}{l}1\phantom{\rule{1em}{0ex}}\phantom{\rule{1em}{0ex}}\phantom{\rule{1em}{0ex}}\phantom{\rule{1em}{0ex}}\phantom{\rule{1em}{0ex}}\phantom{\rule{1em}{0ex}}\phantom{\rule{1em}{0ex}}\phantom{\rule{1em}{0ex}}\phantom{\rule{1em}{0ex}}\left(n=1\right)\\ 2\phantom{\rule{1em}{0ex}}\phantom{\rule{1em}{0ex}}\phantom{\rule{1em}{0ex}}\phantom{\rule{1em}{0ex}}\phantom{\rule{1em}{0ex}}\phantom{\rule{1em}{0ex}}\phantom{\rule{1em}{0ex}}\phantom{\rule{1em}{0ex}}\phantom{\rule{1em}{0ex}}\left(n=2\right)\\ dp\left(n-1\right)+dp\left(n-2\right)\phantom{\rule{1em}{0ex}}\left(n>2\right)\end{array}$

## 斐波那契数列

### 过题代码

#include <cstdio>
using namespace std;

#define LL long long

int main() {
int n;
LL fib[100];
fib[0] = 0;
fib[1] = 1;

for(int i = 2; i <= 70; ++i) {
fib[i] = fib[i - 1] + fib[i - 2];
}
while(scanf("%d", &n) != EOF) {
printf("%lld\n", fib[n]);
}

return 0;
}

# 矩阵快速幂

dp 已经这么快了，还可以优化？看标题↑。

## 算法思想

$fib\left(n\right)=fib\left(n-1\right)+fib\left(n-2\right)\phantom{\rule{1em}{0ex}}$

$\left(\begin{array}{c}fib\left(n\right)\\ fib\left(n-1\right)\end{array}\right)=\left(\begin{array}{cc}1& 1\\ 1& 0\end{array}\right)\left(\begin{array}{c}fib\left(n-1\right)\\ fib\left(n-2\right)\end{array}\right)$

$\left(\begin{array}{c}fib\left(n\right)\\ fib\left(n-1\right)\end{array}\right)={\left(\begin{array}{cc}1& 1\\ 1& 0\end{array}\right)}^{n-1}\left(\begin{array}{c}fib\left(1\right)\\ fib\left(0\right)\end{array}\right)\phantom{\rule{1em}{0ex}}\phantom{\rule{1em}{0ex}}\left(n>0\right)$

## 斐波那契矩阵快速幂裸题

### 题目链接

51Nod 1242: 斐波那契数列的第$N$$N$

### 过题代码

#include <cstdio>
#include <cstring>
using namespace std;

#define LL long long
const LL MOD = 1000000009;
const int SIZE = 2;

struct Matrix {
LL num[SIZE][SIZE];

Matrix() {
memset(num, 0, sizeof(num));
for(int i = 0; i < SIZE; ++i) {
num[i][i] = 1;
}
}
void Set() {
num[0][0] = num[0][1] = num[1][0] = 1;
num[1][1] = 0;
}
void operator*=(const Matrix &b) {
LL ans[SIZE][SIZE];
for(int i = 0; i < SIZE; ++i) {
for(int j = 0; j < SIZE; ++j) {
ans[i][j] = 0;
for(int k = 0; k < SIZE; ++k) {
ans[i][j] = (ans[i][j] + num[i][k] * b.num[k][j] % MOD) % MOD;
}
}
}
memcpy(num, ans, sizeof(ans));
}
};

void mi(Matrix &res, LL n) {
Matrix ans;
for(; n != 0; n >>= 1) {
if((n & 1) == 1) {
ans *= res;
}
res *= res;
}
memcpy(res.num, ans.num, sizeof(ans.num));
}

int main() {
LL n;
Matrix matrix;
scanf("%lld", &n);

matrix.Set();
mi(matrix, n - 1);

printf("%lld", matrix.num[0][0] % MOD);

return 0;
}

# 矩阵快速幂应用

## Okabe and El Psy Kongroo

### 题目链接

Codeforces 821E: Okabe and El Psy Kongroo

### 题意

$n\in \left[1,100\right],a,b,k\in \left[1,{10}^{18}\right],c\in \left[0,15\right]$$n\in[1,100],a,b,k\in[1,10^{18}],c\in[0,15]$ 数据保证${a}_{1}=0,{a}_{n}\le k\le {b}_{n}$$a_1=0,a_n\leq k\leq b_n$，且当$i\in \left[2,n\right]$$i\in[2,n]$ 时，${a}_{i}={b}_{i-1}$$a_i=b_{i-1}$。由于结果可能非常大，将求得的结果对${10}^{9}+7$$10^{9}+7$ 取模。

### 题解

$dp\left(x,y\right)=dp\left(x-1,y\right)+dp\left(x-1,y-1\right)+dp\left(x-1,y+1\right)$

$dp\left(x,0\right)=dp\left(x-1,0\right)+dp\left(x-1,1\right)\phantom{\rule{0ex}{0ex}}dp\left(x,1\right)=dp\left(x-1,0\right)+dp\left(x-1,1\right)+dp\left(x-1,2\right)\phantom{\rule{0ex}{0ex}}dp\left(x,2\right)=dp\left(x-1,1\right)+dp\left(x-1,2\right)+dp\left(x-1,3\right)\phantom{\rule{0ex}{0ex}}\cdots \cdots \phantom{\rule{0ex}{0ex}}dp\left(x,c\right)=dp\left(x-1,c-1\right)+dp\left(x-1,c\right)$

$\left(\begin{array}{c}dp\left(x,0\right)\\ dp\left(x,1\right)\\ dp\left(x,2\right)\\ ⋮\\ dp\left(x,c\right)\end{array}\right)=\left(\begin{array}{ccccc}1& 1& 0& \cdots & 0\\ 1& 1& 1& \cdots & 0\\ 0& 1& 1& \cdots & 0\\ ⋮& ⋮& ⋮& \ddots & ⋮\\ 0& 0& 0& \cdots & 1\end{array}\right)\left(\begin{array}{c}dp\left(x-1,0\right)\\ dp\left(x-1,1\right)\\ dp\left(x-1,2\right)\\ ⋮\\ dp\left(x-1,c\right)\end{array}\right)$

### 过题代码

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <sstream>
#include <cstring>
#include <string>
#include <vector>
#include <list>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <algorithm>
using namespace std;

#define LL long long

const int maxn = 16;
const LL MOD = 1000000007;
struct Matrix {
LL num[maxn][maxn];

Matrix() {
memset(num, 0, sizeof(num));
for(int i = 0; i < maxn; ++i) {
num[i][i] = 1;
}
}
void Set(int Size) {
memset(num, 0, sizeof(num));
for(int i = 0; i < Size; ++i) {
for(int j = i - 1; j <= i + 1; ++j) {
if(j >= 0 && j < Size) {
num[i][j] = 1;
}
}
}
}
void mult(const Matrix &b, const int &Size) {
LL ans[maxn][maxn];
for(int i = 0; i < Size; ++i) {
for(int j = 0; j < Size; ++j) {
ans[i][j] = 0;
for(int k = 0; k < Size; ++k) {
ans[i][j] = (ans[i][j] + num[i][k] * b.num[k][j] % MOD) % MOD;
}
}
}
memcpy(num, ans, sizeof(ans));
}
};
LL N, K, a, b, c, Ans[2][maxn], now;
Matrix tmp;

void mi(Matrix &res, LL n, int Size) {
Matrix ans;
for(; n != 0; n >>= 1) {
if((n & 1) == 1) {
ans.mult(res, Size);
}
res.mult(res, Size);
}
memcpy(res.num, ans.num, sizeof(ans.num));
}

void setZero(LL *num, int n) {
for(int i = n + 1; i < maxn; ++i) {
num[i] = 0;
}
}

int main() {

#ifdef LOCAL
freopen("test.txt", "r", stdin);
#endif // LOCAL

ios::sync_with_stdio(false);

Ans[now][0] = 1;

scanf("%I64d%I64d", &N, &K);

while(N--) {
scanf("%I64d%I64d%I64d", &a, &b, &c);
if(a < K) {
if(b > K) {
b = K;
}
setZero(Ans[now], c);
tmp.Set(c + 1);
mi(tmp, b - a, c + 1);
for(int i = 0; i <= c; ++i) {
Ans[!now][i] = 0;
for(int j = 0; j <= c; ++j) {
Ans[!now][i] = (Ans[!now][i] + tmp.num[i][j] * Ans[now][j] % MOD) % MOD;
}
}
now = !now;
setZero(Ans[now], c);
}
}

printf("%I64d\n", Ans[now][0]);

return 0;
}