目录
题目链接
2016ACM/ICPC亚洲区沈阳站-重现赛(感谢东北大学)
A Thickest Burger
#include <bits/stdc++.h>
using namespace std;
int A, B;
void solve() {
cin >> A >> B;
cout << max(A * 2 + B, A + B * 2) << endl;
}
void Run() {
int T;
cin >> T;
for (int cs = 1; cs <= T; cs++) {
solve();
}
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
Run();
return 0;
}
B Relative atomic mass
#include <bits/stdc++.h>
using namespace std;
int n;
string s;
void solve() {
cin >> s;
n = s.length();
int res = 0;
for (int i = 0; i < n; i++) {
if (s[i] == 'C') {
res += 12;
} else if (s[i] == 'H') {
res += 1;
} else if (s[i] == 'O') {
res += 16;
}
}
cout << res << endl;
}
void Run() {
int T;
cin >> T;
for (int cs = 1; cs <= T; cs++) {
solve();
}
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
Run();
return 0;
}
C Recursive sequence · 矩阵快速幂
https://blog.csdn.net/red_red_red/article/details/90208713
( f n f n − 1 ( n + 1 ) 4 ( n + 1 ) 3 ( n + 1 ) 2 n + 1 1 ) = ( 1 2 1 1 1 4 6 4 1 1 3 3 1 1 2 1 1 1 1 ) ( f n − 1 f n − 2 n 4 n 3 n 2 n 1 ) \begin{pmatrix}f_n\\f_{n-1}\\(n+1)^4\\(n+1)^3\\(n+1)^2\\n+1\\1\end{pmatrix}= \begin{pmatrix}1&2& 1& & & & \\ 1&& & & && \\ && 1& 4& 6& 4& 1\\ && & 1& 3&3& 1\\&& & & 1& 2& 1\\ &&& & & 1& 1\\ && & & & & 1\end{pmatrix} \begin{pmatrix}f_{n-1}\\f_{n-2}\\n^4\\n^3\\n^2\\n\\1\end{pmatrix} ⎝⎜⎜⎜⎜⎜⎜⎜⎜⎛fnfn−1(n+1)4(n+1)3(n+1)2n+11⎠⎟⎟⎟⎟⎟⎟⎟⎟⎞=⎝⎜⎜⎜⎜⎜⎜⎜⎜⎛1121141631432111111⎠⎟⎟⎟⎟⎟⎟⎟⎟⎞⎝⎜⎜⎜⎜⎜⎜⎜⎜⎛fn−1fn−2n4n3n2n1⎠⎟⎟⎟⎟⎟⎟⎟⎟⎞
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int n;
ll a, b;
namespace Matrix {//矩阵快速幂板子
const int maxn = 7;
__int128 mod = 2147493647;
struct Mat {
__int128 mat[maxn][maxn];
void clear() {
memset(mat, 0, sizeof(mat));
}
//初始化成单位矩阵
void initE() {
clear();
for (int i = 0; i < maxn; ++i) {//单位矩阵
mat[i][i] = 1;
}
}
Mat operator*(const Mat a) const {
Mat b;
b.clear();
for (int i = 0; i < maxn; ++i) {
for (int j = 0; j < maxn; ++j) {
for (int k = 0; k < maxn; ++k) {
b.mat[i][j] = (b.mat[i][j] + (mat[i][k] * a.mat[k][j]) % mod + mod) % mod;
}
}
}
return b;
}
};
Mat pow(Mat m, ll k) {
Mat res;
res.initE();
while (k) {
if (k & 1) res = res * m;
k >>= 1;
m = m * m;
}
return res;
}
Mat E;//转移矩阵
Mat f;//最开始的 S1 f1 f0
void init() {
E.clear();
E = {
1, 2, 1, 0, 0, 0, 0,
1, 0, 0, 0, 0, 0, 0,
0, 0, 1, 4, 6, 4, 1,
0, 0, 0, 1, 3, 3, 1,
0, 0, 0, 0, 1, 2, 1,
0, 0, 0, 0, 0, 1, 1,
0, 0, 0, 0, 0, 0, 1
};
f = {
b, 0, 0, 0, 0, 0, 0,
a, 0, 0, 0, 0, 0, 0,
81, 0, 0, 0, 0, 0, 0,
27, 0, 0, 0, 0, 0, 0,
9, 0, 0, 0, 0, 0, 0,
3, 0, 0, 0, 0, 0, 0,
1, 0, 0, 0, 0, 0, 0,
};
}
}
using namespace Matrix;
void solve() {
cin >> n >> a >> b;
if (n == 1) {
cout << a << endl;
} else if (n == 2) {
cout << b << endl;
} else {
init();
cout << (ll)((pow(E, n - 2) * f).mat[0][0]) << endl;
}
}
void Run() {
int T;
cin >> T;
for (int cs = 1; cs <= T; cs++) {
solve();
}
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
Run();
return 0;
}
D Winning an Auction
E Counting Cliques · 暴力
#include <bits/stdc++.h>
using namespace std;
vector<int> e[105];
int n, m, s;
int mp[105][105], vis[105];
int Stack[105], top = 0;
bool check(int u) {
for (int i = 1; i <= top; i++) {
if (i == u) continue;
if (!mp[Stack[i]][u]) return false;
}
return true;
}
int res = 0;
void calc(int u) {
Stack[++top] = u;
if (top == s) {
res++;
}
if (top < s) {
for (int v:e[u]) {
if (check(v)) {
calc(v);
}
}
}
top--;
}
void solve() {
cin >> n >> m >> s;
for (int i = 1, u, v; i <= m; i++) {
cin >> u >> v;
if (u > v)swap(u, v);
if (!mp[u][v]) {
mp[u][v] = 1;
e[u].push_back(v);
}
}
for (int i = 1; i <= n; i++) {
sort(e[i].begin(), e[i].end());
}
for (int i = 1; i <= n; i++) {
calc(i);
}
cout << res << endl;
// init
res = 0;
for (int i = 1; i <= n; i++) {
e[i].clear();
vis[i] = 0;
for (int j = i + 1; j <= n; j++) {
mp[i][j] = 0;
}
}
}
void Run() {
int T;
cin >> T;
for (int cs = 1; cs <= T; cs++) {
solve();
}
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
Run();
return 0;
}
F Similar Rotations
G Do not pour out
H Guessing the Dice Roll · AC自动机+矩阵/马尔科夫链
https://www.cnblogs.com/dirge/p/6017703.html
初学马尔科夫链 - https://zhuanlan.zhihu.com/p/52376035
假设存在两个猜想
.
.
.
123
...123
...123
234...
234...
234...
若要让第二个猜想成立,第一个猜想就必须不成立,
如果当前局势使得第一个猜想成立,那么当
3
3
3出现的那一刻,游戏结束,
这种概率题永远优先猜马尔科夫链,可惜转移矩阵不会写,万万没想到居然是借助ac自动机…
通过AC自动机得到马尔科夫链的有向图,每个节点都视为一个状态,
大致写写想想可以知道:肯定存在一个初始状态0,作为游戏的开始状态,其状态概率必定为1
如果当前状态为某一个猜想的结尾,则当前状态对于其他状态的转移概率均为0
如果当前状态非结尾,则其概率为 ∑ \sum ∑ 前一个状态的概率 × \times × 概率转移矩阵里 A A A(前一个状态->当前状态)
设
x
n
x_n
xn为每个状态的概率,
V
k
V^k
Vk 为第k步的状态向量
V
k
=
(
x
0
x
1
.
.
.
x
n
)
V^k=\begin{pmatrix}x_0\\x_1\\...\\x_n\end{pmatrix}
Vk=⎝⎜⎜⎛x0x1...xn⎠⎟⎟⎞
则初始状态
V
0
V^0
V0
V
0
=
(
1
0
.
.
.
0
)
V^0=\begin{pmatrix}1\\0\\...\\0\end{pmatrix}
V0=⎝⎜⎜⎛10...0⎠⎟⎟⎞
马尔科夫链的转移只和前一个状态有关,与之前的之前状态无关,每次一步转移均有
V
n
+
1
=
A
×
V
n
V^{n+1}=A\times V^n
Vn+1=A×Vn
就是这个东西👇(借一下博客里的图)
然后就是矩阵乘啊乘啊乘,因为转移矩阵最后会收敛,所以只要一直等到矩阵稳定就行…看起来好像是这样,可惜这种方法只会使误差越来越大…
真正关键是这个公式:
x
=
(
∑
i
=
1
∞
A
i
)
b
x=(\sum_{i=1}^{∞}A^i)b
x=(i=1∑∞Ai)b
左边矩阵
x
x
x为最终状态,
A
A
A为转移矩阵,右边矩阵
b
b
b为初始状态
不好意思,我学的时候学到的公式是第一个,这个着实不会…
有没有大神能讲一下,为啥公式可以写成这样…
反正就强记这个叫做矩阵函数的东西,百度说这个函数是收敛的
∑
i
=
1
∞
A
i
=
(
E
−
A
)
−
1
\sum_{i=1}^{∞}A^i=(E-A)^{-1}
i=1∑∞Ai=(E−A)−1
所以就化成 x = ( E − A ) − 1 b x=(E-A)^{-1}b x=(E−A)−1b ( E − A ) x = b (E-A)x=b (E−A)x=b
高斯消元求解x,这题有点卡精度
#include <bits/stdc++.h>
using namespace std;
const double eps = 1e-10;
const int N = 1e6 + 10;
int a[15][15];
int n, L;
struct AC {
static const int maxn = 7;
struct Trie {
int fail;
int son[maxn];
int end;
} AC[N];
int dfn = 0;
Trie operator[](const int x) {
return AC[x];
}
void clear(int x) {
memset(AC[x].son, 0, sizeof AC[x].son);
AC[x].fail = AC[x].end = 0;
}
void insert(int *s, int len, int id) {
int now = 0;
for (int i = 1; i <= len; i++) {
if (AC[now].son[s[i]] == 0) {
AC[now].son[s[i]] = ++dfn;
clear(dfn);
}
now = AC[now].son[s[i]];
}
AC[now].end = id;
}
queue<int> q;
void get_fail() {
for (int i = 0; i < maxn; i++) {
if (AC[0].son[i]) {
AC[AC[0].son[i]].fail = 0;
q.push(AC[0].son[i]);
}
}
while (!q.empty()) {
int u = q.front();
q.pop();
for (int i = 0; i < maxn; i++) {
if (AC[u].son[i]) {
AC[AC[u].son[i]].fail = AC[AC[u].fail].son[i];
q.push(AC[u].son[i]);
} else {
AC[u].son[i] = AC[AC[u].fail].son[i];
}
}
}
}
void init() {
dfn = 0;
clear(0);
}
} AC;
double A[205][205];
// 高斯消元板子
int Gauss(int n) {
int c, r; // col row
for (c = 1, r = 1; c <= n; c++) {
int t = r;
for (int i = r; i <= n; i++) {
if (fabs(A[i][c]) > fabs(A[t][c]))
t = i;
}
if (fabs(A[t][c]) < eps) continue;
swap(A[t], A[r]);
for (int i = n + 1; i >= c; i--) {
A[r][i] /= A[r][c];
}
for (int i = r + 1; i <= n; i++) {
if (fabs(A[i][c]) > eps) {
for (int j = n + 1; j >= c; j--) {
A[i][j] -= A[r][j] * A[i][c];
}
}
}
r++;
}
if (r != n + 1) {
for (int i = r; i <= n; i++) {
if (fabs(A[i][n + 1]) > eps) return 2;
}
return 0;//无解
}
for (int i = n; i; i--) {
for (int j = i + 1; j <= n; j++) {
A[i][n + 1] -= A[j][n + 1] * A[i][j];
}
}
return 1;
}
double res[N];
void solve() {
cin >> n >> L;
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= L; j++) {
cin >> a[i][j];
}
AC.insert(a[i], L, i);
}
AC.get_fail();
//获得马尔科夫链后
// V(n)= (Σ_{k->∞} A^k) V(0)
// V(n)=(E-A)^{-1}V(0)
// (E-A)V(n)=V(0)
// 转化成高斯消元 (E-A)X=b 求解x
memset(A, 0, sizeof A);
// 高斯消元 col:1~n+1 row:1~n
// 所以需要A[x][y]中的x,y都需要偏移一位
for (int i = 0; i <= AC.dfn; i++) {
A[i + 1][i + 1] = 1.0;
}
for (int i = 0; i <= AC.dfn; i++) {
for (int j = 1; j <= 6; j++) {
if (!AC[i].end) {
int to = AC[i].son[j];
A[to + 1][i + 1] -= 1.0 / 6;
}
}
}
A[1][(AC.dfn + 1) + 1] = 1.0;
Gauss(AC.dfn + 1);
for (int i = 1; i <= AC.dfn; i++) {
if (AC[i].end) {
res[AC[i].end] = A[i + 1][(AC.dfn + 1) + 1];
}
}
for (int i = 1; i <= n; i++) {
cout << fixed << setprecision(6) << res[i] << " \n"[i == n];
}
AC.init();
}
void Run() {
int T;
cin >> T;
for (int cs = 1; cs <= T; cs++) {
solve();
}
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
Run();
return 0;
}
I The Elder
J Query on a graph
K New Signal Decomposition
L A Random Turn Connection Game
M Subsequence