# T1、数字

$s_i$ 表示将 $1$$i$ 依次相连得到的字符串；
$T \ (T \leq 10 ^ 4)$ 组询问，每次输出使 $n \ (n \leq 10 ^{18})$ 作为子串出现在 $s_x$ 中最小的 $x$

## $Sol$：

1、$x = n$
2、$n$ 被分成两部分，前半部分为 $x - 1$ 的后缀，后半部分为 $x$ 的前缀；
3、$n$ 被分成若干部分，存在数完整地出现在 $n$ 中。

## $Source： #include <cstdio> #include <algorithm> int in() { int x = 0; char c = getchar(); bool f = 0; while (c < '0' || c > '9') f |= c == '-', c = getchar(); while (c >= '0' && c <= '9') x = (x << 1) + (x << 3) + (c ^ 48), c = getchar(); return f ? -x : x; } long long lin() { long long x = 0; char c = getchar(); bool f = 0; while (c < '0' || c > '9') f |= c == '-', c = getchar(); while (c >= '0' && c <= '9') x = (x << 1) + (x << 3) + (c ^ 48), c = getchar(); return f ? -x : x; } template<typename T>inline void chk_min(T &_, T __) { _ = _ < __ ? _ : __; } template<typename T>inline void chk_max(T &_, T __) { _ = _ > __ ? _ : __; } long long n, Pow[105]; int nn; //Devide into 3 parts begin long long calc(const int len) { int sub_len; bool flag; long long tmp, min = 1ll << 60ll; for (int i = nn, j, k; i + len > nn && i - len >= 0; --i) { long long now = n / Pow[nn - i] % Pow[len]; tmp = now; flag = 0; if (i != nn) { ++tmp; sub_len = len + (tmp == Pow[len]); if (!(n % Pow[nn - i] / Pow[nn - i - 1]) || tmp / Pow[sub_len - (nn - i)] != n % Pow[nn - i]) flag = 1; } if (flag == 1) continue; j = i, k = len; while (now && j - k > 0) { if (!(now / Pow[k - 1]) || now != n / Pow[nn - j] % Pow[k]) { flag = 1; break; } j -= k; if (now == Pow[k - 1]) --k; --now; } if (j) { if (n / Pow[nn - j] != now % Pow[j]) flag = 1; } if (!flag) { chk_min(min, tmp); } } return min; } //Devide into 3 parts end int main() { //freopen("in", "r", stdin); freopen("number.in", "r", stdin); freopen("number.out", "w", stdout); int T = in(); long long res; Pow[0] = 1; for (int i = 1; i <= 17; ++i) Pow[i] = Pow[i - 1] * 10; while (T--) { long long tmp; n = res = tmp = lin(), nn = 0; while (tmp) tmp /= 10, ++nn; tmp = n; //Devide into 2 parts begin for (int i = 1; i < nn; ++i) { if (n % Pow[nn - i] / Pow[nn - i - 1]) { for (int j = std::max(i, nn - i); j < nn; ++j) { if (n % Pow[nn - j] == (n / Pow[nn - i] + 1) % Pow[i] / Pow[i - (nn - j)]) { chk_min(res, (n / Pow[nn - i] + 1) % Pow[i] + n % Pow[nn - i] / Pow[nn - j] * Pow[i]); } } chk_min(res, (n / Pow[nn - i] + 1) % Pow[i] + n % Pow[nn - i] * Pow[i]); } } //Devide into 2 parts end for (int i = 1; tmp; ++i, tmp /= 10) { chk_min(res, calc(i)); } printf("%lld\n", res); } return 0; }  # T2、Maja 题目链接 给定一个 $n \times m \ (n, m \leq 100)$ 的四联通网格，到达 $(i, j)$ 可以获得 $C_{i,j} \ (0 \leq C_{i,j} \leq 10 ^ 9)$ 的得分 (可重复获得)； 给定起点为 $(A, B) \ (1 \leq A \leq n, 1 \leq B \leq m)$，求恰好走 $k \ (k \leq 10 ^ 9)$ 步后回到起点的最大得分。 保证 $2 | k$$C_{i,j} = 0$ ## $Sol$： 由于 $k$ 很大，最优解一定是走过一段路径后一直重复走一个循环； 可以证明重复路径一定是相邻的两个格子； $prf$ 对于任意一段重复路径，一定可以找到两个格子的得分平均值不小于一整段重复路径的平均值。 $Q.E.D.$ $f_{i, x, y}$ 表示走 $i$ 步到达 $(x,y)$ 的最大价值，再在与之四联通的格子中选择得分最高的走$\frac { k - 2i }{2} \$ 次循环；
$i$ 最多到 $\min \{nm, \frac{k}{2} \}$

## $Source$：

#include <cstdio>
#include <cstring>
#include <algorithm>
int in() {
int x = 0; char c = getchar(); bool f = 0;
while (c < '0' || c > '9')
f |= c == '-', c = getchar();
while (c >= '0' && c <= '9')
x = (x << 1) + (x << 3) + (c ^ 48), c = getchar();
return f ? -x : x;
}
template<typename T>inline void chk_min(T &_, T __) { _ = _ < __ ? _ : __; }
template<typename T>inline void chk_max(T &_, T __) { _ = _ > __ ? _ : __; }

const int N = 105;
int n, m, A, B, k;
int mp[N][N];
long long f[2][N][N], res;

void work() {
int cur = 0, lim = std::min(n * m, k >> 1);
memset(f[0], -1, sizeof(f[0]));
f[0][A][B] = 0;
for (int i = 0; i < lim; ++i, cur ^= 1) {
memset(f[cur ^ 1], -1, sizeof(f[cur ^ 1]));
for (int x = 1; x <= n; ++x) {
for (int y = 1; y <= m; ++y) {
if (!~f[cur][x][y])
continue;
if (i + i < k) {
int max = -1;
chk_max(max, mp[x + 1][y]);
chk_max(max, mp[x - 1][y]);
chk_max(max, mp[x][y + 1]);
chk_max(max, mp[x][y - 1]);
chk_max(res, f[cur][x][y] + f[cur][x][y] - mp[x][y] + 1ll * (k - i - i) / 2 * (mp[x][y] + max));
}
if (x < n)
chk_max(f[cur ^ 1][x + 1][y], f[cur][x][y] + mp[x + 1][y]);
if (x)
chk_max(f[cur ^ 1][x - 1][y], f[cur][x][y] + mp[x - 1][y]);
if (y < m)
chk_max(f[cur ^ 1][x][y + 1], f[cur][x][y] + mp[x][y + 1]);
if (y)
chk_max(f[cur ^ 1][x][y - 1], f[cur][x][y] + mp[x][y - 1]);
}
}
}
if (lim + lim <= k) {
for (int x = 1; x <= n; ++x)
for (int y = 1; y <= m; ++y)
if (~f[cur][x][y])
chk_max(res, f[cur][x][y] + f[cur][x][y] - mp[x][y]);
}
printf("%lld\n", res);
}

int main() {
//freopen("in", "r", stdin);
freopen("maja.in", "r", stdin);
freopen("maja.out", "w", stdout);
n = in(), m = in(), A = in(), B = in(), k = in();
for (int i = 1; i <= n; ++i)
for (int j = 1; j <= m; ++j)
mp[i][j] = in();
work();
return 0;
}


# T3、djq的朋友圈

$n \ (n \leq 42)$ 个人，编号为 $1$ ~ $n$，关系分 $0、1$ 两种，已知 $m$ 组关系 (两个人不会的关系不会给出两次)，想知道 $1$ 与其他人的关系；

$1$ 与他关系已知，那么两者关系不会改变 (关系是双向的)；

## $Sol$：

$|A| \leq 20$，可以将 $A$ 状压，记 $f_i$ 表示 $i$ 这些人已经出现在列表上的最优解，枚举下一个出现的人即可。

## $Source$：

#include <cstdio>
#include <cstring>
#include <algorithm>
int in() {
int x = 0; char c = getchar(); bool f = 0;
while (c < '0' || c > '9')
f |= c == '-', c = getchar();
while (c >= '0' && c <= '9')
x = (x << 1) + (x << 3) + (c ^ 48), c = getchar();
return f ? -x : x;
}
template<typename T>inline void chk_min(T &_, T __) { _ = _ < __ ? _ : __; }
template<typename T>inline void chk_max(T &_, T __) { _ = _ > __ ? _ : __; }

const int N = 51;

int n, m, cnt_a, cnt_b, tot_st, t[N][N], mp[N], id[N], f[1 << 21 | 1];
long long fri[N], agn[N];

int bit_cnt(long long x, int ret = 0) {
for (; x; x &= (x - 1), ++ret);
return ret;
}

namespace A {
void work() {
tot_st = (1 << cnt_a) - 1;
for (int i = 2; i <= n; ++i)
if (~t[1][i])
id[mp[i]] = i;
for (int i = 0; i < tot_st; ++i) {
long long now = 0;
for (int j = 1; j <= cnt_a; ++j)
if (i & (1 << (j - 1)))
now |= (fri[id[j]] | agn[id[j]]);
for (int j = 1; j <= cnt_a; ++j)
if (~i & (1 << (j - 1))) {
if (!t[1][id[j]]) {
chk_max(f[i | (1 << (j - 1))], f[i] + bit_cnt(~now & fri[id[j]]));
} else {
chk_max(f[i | (1 << (j - 1))], f[i] + bit_cnt(~now & agn[id[j]]));
}
}
}
for (int i = 1; i <= cnt_a; ++i)
f[tot_st] += (t[1][id[i]] == 0);
printf("%d\n", f[tot_st]);
}
}

namespace B {
void work() {
tot_st = (1 << cnt_b) - 1;
for (int i = 2; i <= n; ++i)
if (~t[1][i])
id[mp[i]] = i;
for (int i = 0; i < tot_st; ++i) {
for (int j = 1; j <= cnt_a; ++j)
if (~i & (fri[id[j]] | agn[id[j]])) {
if (!t[1][id[j]]) {
chk_max(f[i | fri[id[j]] | agn[id[j]]], f[i] + bit_cnt(~i & fri[id[j]]));
} else {
chk_max(f[i | fri[id[j]] | agn[id[j]]], f[i] + bit_cnt(~i & agn[id[j]]));
}
}
}
for (int i = 1; i <= cnt_a; ++i)
f[tot_st] += (t[1][id[i]] == 0);
printf("%d\n", f[tot_st]);
}
}

int main() {
//freopen("in", "r", stdin);
freopen("friends.in", "r", stdin);
freopen("friends.out", "w", stdout);
n = in(), m = in();
memset(t, -1, sizeof(t));
for (int i = 1, x, y; i <= m; ++i) {
x = in(), y = in();
t[x][y] = t[y][x] = in();
}

for (int i = 2; i <= n; ++i) {
if (!~t[1][i])
continue;
mp[i] = ++cnt_a;
for (int j = 2; j <= n; ++j) {
if (!~t[1][j] && ~t[i][j]) {
if (!mp[j])
mp[j] = ++cnt_b;
if (!t[i][j])
fri[i] |= (1ll << (mp[j] - 1));
else
agn[i] |= (1ll << (mp[j] - 1));
}
}
}

if (cnt_a <= 20) {
A::work();
} else {
B::work();
}
return 0;
}

posted @ 2019-08-21 22:00  15owzLy1  阅读(92)  评论(0编辑  收藏