1、线性分类器
#include <iostream>
#include <algorithm>
#include <set>
using namespace std;
typedef long long LL;
const int N = 1010;
int n, m;
struct Node {
int x, y;
char type;
} node[N];
int p0, p1, p2;
set<char> st_u, st_d;
bool get(int x, int y) {
return p0 + (LL) x * p1 + (LL) y * p2 > 0;
}
int main() {
cin >> n >> m;
for (int i = 0; i < n; i++) cin >> node[i].x >> node[i].y >> node[i].type;
while (m--) {
cin >> p0 >> p1 >> p2;
st_u.clear(), st_d.clear();
for (int i = 0; i < n; i++) {
int res = get(node[i].x, node[i].y);
if (res > 0) st_u.insert(node[i].type);
else st_d.insert(node[i].type);
}
if (st_d.size() > 1 || st_u.size() > 1) puts("No"); else puts("Yes");
}
return 0;
}
2、稀疏向量(双指针)
#include <iostream>
#include <algorithm>
using namespace std;
#define x first
#define y second
typedef long long LL;
typedef pair<int, int> PII;
const int N = 5e5 + 10;
int n, a, b;
PII A[N], B[N];
int main() {
scanf("%d%d%d", &n, &a, &b);
for (int i = 0; i < a; i++) scanf("%d%d", &A[i].x, &A[i].y);
for (int i = 0; i < b; i++) scanf("%d%d", &B[i].x, &B[i].y);
sort(A, A + a);
sort(B, B + b);
LL res = 0;
for (int i = 0, j = 0; i < a && j < b;)
if (A[i].x < B[j].x) i++;
else if (A[i].x > B[j].x) j++;
else res += (LL) A[i].y * B[j].y, i++, j++;
printf("%lld", res);
return 0;
}
3、Markdown渲染器
4、1246
首先,由题目可知:
- 1:2
- 2:4
- 4:1,6
- 6:6,4
也就是说, 2 2 2 可以由 1 1 1 转换过来, 4 4 4 可以由 2 、 6 2、6 2、6 转换过来…
当 S = 1 S= 1 S=1 的时候,可以发现时刻 n n n 的状态是完全取决于时刻 n − 1 n-1 n−1 的状态。也就是有转移方程:
- f ( n , 1 ) = f ( n − 1 , 4 ) f(n, 1) = f(n-1, 4) f(n,1)=f(n−1,4)
- f ( n , 2 ) = f ( n − 1 , 1 ) f(n, 2) = f(n- 1, 1) f(n,2)=f(n−1,1)
- f ( n , 4 ) = f ( n − 1 , 2 ) + f ( n − 1 , 6 ) f(n, 4) = f(n - 1, 2) + f(n-1, 6) f(n,4)=f(n−1,2)+f(n−1,6)
- f ( n , 6 ) = f ( n − 1 , 4 ) + f ( n − 1 , 6 ) f(n, 6) = f(n-1,4) + f(n-1,6) f(n,6)=f(n−1,4)+f(n−1,6)
当 S = 2 S = 2 S=2 的时候,这两位数可能存在两种构造情况:
- 由上一个状态的一个数产生,比如 4 4 4 可以产生 16 16 16, 6 6 6 可以产生 64 64 64。
- 由上一个状态的两个相邻的数产生。
那么就存在如下规律:
- 1:2
- 2:4
- 4:1,6,16
- 6:6,4,64
- 16:26 (1产生2,6产生64,取前两位)
- 26:46
- 41:62
- 42:64
- 44:61
- 46:66
- 61:42
- 62:44
- 64:41
- 66:46
可见可以产生的两位数总共仅有 14 14 14 总,且第 n n n 行的两位数完全取决于第 n − 1 n-1 n−1 行两位数的状态。
分析到这里可以考虑使用矩阵快速幂进行状态转移(根据数据,处理出 S = 1 、 S = 2 S= 1、S = 2 S=1、S=2 的情况,已经可以拿到96分!)。
#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;
typedef long long LL;
const int N = 14, MOD = 998244353;
int n;
string S;
int id[100]; // 将下面14个数映射成从0开始的id
vector<int> vers{1, 2, 4, 6, 16, 26, 41, 42, 44, 46, 61, 62, 64, 66};
vector<vector<int>> g{{2}, {4}, {1, 6, 16}, {6, 4, 64}, {26}, {46}, {62}, {64}, {61}, {66}, {42}, {44}, {41}, {46}};
int tr[N][N]; // 转移矩阵
void init() {
memset(id, -1, sizeof id);
for (int i = 0; i < N; i++) id[vers[i]] = i;
for (int i = 0; i < N; i++)
for (auto x: g[i])
tr[i][id[x]]++;
}
// 矩阵乘法
void mul(int c[][N], int a[][N], int b[][N]) {
static int tmp[N][N];
memset(tmp, 0, sizeof tmp);
for (int i = 0; i < N; i++)
for (int j = 0; j < N; j++)
for (int k = 0; k < N; k++)
tmp[i][j] = (tmp[i][j] + (LL) a[i][k] * b[k][j]) % MOD;
memcpy(c, tmp, sizeof tmp);
}
int qmi(int k, int id) {
if (id == -1) return 0;
int res[N][N] = {0}, w[N][N];
memcpy(w, tr, sizeof w);
res[0][0] = 1;
while (k) {
if (k & 1) mul(res, res, w);
mul(w, w, w);
k >>= 1;
}
return res[0][id];
}
int main() {
init();
cin >> n >> S;
cout << qmi(n, id[stoi(S)]) << endl;
return 0;
}
考虑 S > 2 S > 2 S>2 的情况,因为有如下关系:
- 1:2
- 2:4
- 4:16
- 6:64
对于任意一串数据,可以根据第一个数的开头数字确定它是由哪个数转移过来的,比如:
64162641664
64162641664
64162641664
对于任一个一数,它的构成只可能存在两种情况,比如
164
164
164
对于中间的
6
6
6 而言,它可能和前面的
1
1
1 一起,是由上一个状态的
4
4
4 产生,也可能是和后面的
4
4
4 一起,是由上一个状态的
6
6
6 产生的。
所以对于一串数的首位而言,可能存在三种情况:
- 首位直接匹配;
- 首位是 4 4 4,可以在前面添加一个 6 6 6;
- 首位是 6 6 6,可以在前面添加一个 1 1 1。
而对于末位,可能存在位不足,需要特判。比如单独留下一个 6 6 6,这种情况可以认为它的上一个状态是 6 6 6;如果单独留下一个 1 1 1,那么可以认为它的上一个状态是 4 4 4。
可以暴力枚举它的所有情况,一层层往上迭代就转换为了上面的 S = 1 、 S = 2 S = 1、S = 2 S=1、S=2 的问题。
#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;
typedef long long LL;
const int N = 14, MOD = 998244353;
int n;
string S;
int id[100]; // 将下面14个数映射成从0开始的id
vector<int> vers{1, 2, 4, 6, 16, 26, 41, 42, 44, 46, 61, 62, 64, 66};
vector<vector<int>> g{{2}, {4}, {1, 6, 16}, {6, 4, 64}, {26}, {46}, {62}, {64}, {61}, {66}, {42}, {44}, {41}, {46}};
int tr[N][N]; // 转移矩阵
void init() {
memset(id, -1, sizeof id);
for (int i = 0; i < N; i++) id[vers[i]] = i;
for (int i = 0; i < N; i++)
for (auto x: g[i])
tr[i][id[x]]++;
}
void mul(int c[][N], int a[][N], int b[][N]) {
static int tmp[N][N];
memset(tmp, 0, sizeof tmp);
for (int i = 0; i < N; i++)
for (int j = 0; j < N; j++)
for (int k = 0; k < N; k++)
tmp[i][j] = (tmp[i][j] + (LL) a[i][k] * b[k][j]) % MOD;
memcpy(c, tmp, sizeof tmp);
}
int qmi(int k, int id) {
if (id == -1) return 0;
int res[N][N] = {0}, w[N][N];
memcpy(w, tr, sizeof w);
res[0][0] = 1;
while (k) {
if (k & 1) mul(res, res, w);
mul(w, w, w);
k >>= 1;
}
return res[0][id];
}
string get(string str) {
string res;
for (int i = 0; i < str.size(); i++)
if (str[i] == '2') res += '1';
else if (str[i] == '4') res += '2';
else if (str[i] == '1') {
if (i + 1 == str.size() || str[i + 1] == '6') res += '4', i++; else return "";
} else {
if (i + 1 == str.size() || str[i + 1] == '4') res += '6', i++; else return "";
}
return res;
}
int dfs(int k, string &str) {
if (str.size() <= 2) return qmi(k, id[stoi(str)]);
int res = 0;
for (string s: {"", "1", "6"}) {
auto t = get(s + str);
if (t.size()) res = (res + dfs(k - 1, t)) % MOD;
}
return res;
}
int main() {
init();
cin >> n >> S;
cout << dfs(n, S) << endl;
return 0;
}