Day 1
T1 rps
模拟题。根据(i−1)modNA+1和(i−1)modNB+1的值判断这一次的胜负来统计答案。
代码:
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
inline int read() {
int res = 0; bool bo = 0; char c;
while (((c = getchar()) < '0' || c > '9') && c != '-');
if (c == '-') bo = 1; else res = c - 48;
while ((c = getchar()) >= '0' && c <= '9')
res = (res << 3) + (res << 1) + (c - 48);
return bo ? ~res + 1 : res;
}
const int N = 205;
int ac[5][5] = {
{0, -1, 1, 1, -1},
{1, 0, -1, 1, -1},
{-1, 1, 0, -1, 1},
{-1, -1, 1, 0, 1},
{1, 1, -1, -1, 0}
}, n, na, nb, cnt1, cnt2, a[N], b[N];
int main() {
//freopen("rps.in", "r", stdin);
//freopen("rps.out", "w", stdout);
int i; n = read(); na = read(); nb = read();
for (i = 1; i <= na; i++) a[i] = read();
for (i = 1; i <= nb; i++) b[i] = read();
for (i = 1; i <= n; i++) {
int x = a[(i - 1) % na + 1], y = b[(i - 1) % nb + 1];
if (ac[x][y] == 1) cnt1++;
else if (ac[x][y] == -1) cnt2++;
}
printf("%d %d\n", cnt1, cnt2);
return 0;
}
T2 link
考虑到u和
1、
2、
对于情况
对于情况2,先枚举
对于寻找最大值,找出fa的权值最大的两个子节点,用它们权值的积更新答案。
对于求和,先不考虑是否选了两个相同的子节点。
设sum为fa的子节点权值和,那么如果固定一个子节点u,那么所有的子节点都可以充当
然后从sum2中去除掉选了同一个子节点的情况,就可以计入答案了。
注意:1、最大值不要取模。2、合法点对(u,v)和(v,u)是两个不同的点对。
代码:
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
inline int read() {
int res = 0; bool bo = 0; char c;
while (((c = getchar()) < '0' || c > '9') && c != '-');
if (c == '-') bo = 1; else res = c - 48;
while ((c = getchar()) >= '0' && c <= '9')
res = (res << 3) + (res << 1) + (c - 48);
return bo ? ~res + 1 : res;
}
typedef long long ll;
const int N = 2e5 + 5, PYZ = 10007;
int n, tot, a[N], w[N], ecnt, nxt[N << 1], adj[N], go[N << 1], sum;
ll mv;
void add_edge(int u, int v) {
nxt[++ecnt] = adj[u]; adj[u] = ecnt; go[ecnt] = v;
nxt[++ecnt] = adj[v]; adj[v] = ecnt; go[ecnt] = u;
}
bool comp(int x, int y) {
return w[x] < w[y];
}
void dfs(int u, int fu) {
int i; tot = 0; ll res = 0, tmp = 0;
for (int e = adj[u], v; e; e = nxt[e])
if ((v = go[e]) != fu) a[++tot] = v, res += w[v],
tmp += 1ll * w[v] * w[v];
sort(a + 1, a + tot + 1, comp); ll tm = sum;
(sum += ((res % PYZ) * (res % PYZ) - tmp % PYZ) % PYZ + PYZ) %= PYZ;
if (tot >= 2) mv = max(mv, 1ll * w[a[tot - 1]] * w[a[tot]]);
if (fu) {
mv = max(mv, 1ll * w[fu] * w[a[tot]]);
(sum += 2ll * w[fu] * res % PYZ) %= PYZ;
}
for (int e = adj[u], v; e; e = nxt[e])
if ((v = go[e]) != fu) dfs(v, u);
}
int main() {
//freopen("link.in", "r", stdin);
//freopen("link.out", "w", stdout);
int i, x, y; n = read();
for (i = 1; i < n; i++) x = read(), y = read(), add_edge(x, y);
for (i = 1; i <= n; i++) w[i] = read();
dfs(1, 0); cout << mv << " " << sum << endl;
return 0;
}
T3 bird
完全背包DP。设f[i][j]为到了位置(i,j)的最少点击次数,如果无法到达则为∞。一开始先把f的所有数初始化为
边界为:
∀0<j≤m,f[0][j]=0
转移:
1、当j=m时,
∀0≤k<m,f[i][j]=min(f[i][j],f[i−1][k]+⌊j−k−1Xi−1⌋+1)
f[i][j]=min(f[i][j],f[i−1][m]+1)。
(即当高度达到m时继续操作则保持高度)
2、当
如果j≥Xi−1∗2,则
f[i][j]=min(f[i][j],min(f[i−1][j−Xi−1]+1,f[i][j−Xi−1]+1))
否则f[i][j]=min(f[i][j],f[i−1][j−Xi−1]+1)
(即此操作上升)
3、当j≤m−Yi−1时,
f[i][j]=min(f[i][j],f[i−1][j+Yi−1])
(即此操作下降)
注意一些细节。
代码:
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
inline int read() {
int res = 0; bool bo = 0; char c;
while (((c = getchar()) < '0' || c > '9') && c != '-');
if (c == '-') bo = 1; else res = c - 48;
while ((c = getchar()) >= '0' && c <= '9')
res = (res << 3) + (res << 1) + (c - 48);
return bo ? ~res + 1 : res;
}
const int N = 1e4 + 5, M = 1005, INF = 0x3f3f3f3f;
int n, m, K, X[N], Y[N], U[N], D[N], f[N][M];
bool is[N];
void chkmin(int &a, int b) {a = min(a, b);}
int main() {
//freopen("bird.in", "r", stdin);
//freopen("bird.out", "w", stdout);
int i, j, k, x, cnt = 0; n = read(); m = read(); K = read(); U[n] = m + 1;
for (i = 0; i < n; i++) X[i] = read(), Y[i] = read(), U[i] = m + 1;
for (i = 1; i <= K; i++) x = read(), D[x] = read(), U[x] = read(),
is[x] = 1;
for (i = 1; i <= n; i++) for (j = 0; j <= m + 1; j++) f[i][j] = INF;
for (i = 1; i <= n; i++) {
for (j = 0; j <= m; j++) {
if (j == m) {
for (k = 0; k <= m; k++)
chkmin(f[i][j], f[i - 1][k] + (
k == m ? 1 : (j - k - 1) / X[i - 1] + 1));
continue;
}
if (j >= X[i - 1]) {
if (j >= (X[i - 1] << 1)) chkmin(f[i][j],
min(f[i - 1][j - X[i - 1]] + 1, f[i][j - X[i - 1]] + 1));
else chkmin(f[i][j], f[i - 1][j - X[i - 1]] + 1);
}
}
for (j = 0; j <= m - Y[i - 1]; j++)
chkmin(f[i][j], f[i - 1][j + Y[i - 1]]);
for (j = 0; j <= D[i]; j++) f[i][j] = INF;
for (j = U[i]; j <= m + 1; j++) f[i][j] = INF;
if (is[i]) {
bool flag = 0;
for (j = D[i] + 1; j <= U[i] - 1; j++)
if (f[i][j] < INF) {flag = 1; break;}
if (flag) cnt++;
}
}
int res = INF;
for (j = 1; j <= m; j++) chkmin(res, f[n][j]);
if (res < INF) printf("1\n%d\n", res);
else printf("0\n%d\n", cnt);
return 0;
}
Day 2
T1 wireless
模拟题,暴力枚举每个区域即可。注意边界。
代码:
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
inline int read() {
int res = 0; bool bo = 0; char c;
while (((c = getchar()) < '0' || c > '9') && c != '-');
if (c == '-') bo = 1; else res = c - 48;
while ((c = getchar()) >= '0' && c <= '9')
res = (res << 3) + (res << 1) + (c - 48);
return bo ? ~res + 1 : res;
}
const int N = 134;
int d, n, a[N][N];
int check(int x, int y) {
int i, j, x1, y1, x2, y2, ans = 0;
x1 = max(0, x - d); y1 = max(0, y - d);
x2 = min(128, x + d); y2 = min(128, y + d);
for (i = x1; i <= x2; i++) for (j = y1; j <= y2; j++)
ans += a[i][j]; return ans;
}
int main() {
//freopen("wireless.in", "r", stdin);
//freopen("wireless.out", "w", stdout);
int i, j, tot = 0, ans = 0; d = read(); n = read();
for (i = 1; i <= n; i++) a[read()][read()] = read();
for (i = 0; i <= 128; i++) for (j = 0; j <= 128; j++)
ans = max(ans, check(i, j));
for (i = 0; i <= 128; i++) for (j = 0; j <= 128; j++)
tot += (check(i, j) == ans);
printf("%d %d\n", tot, ans);
return 0;
}
T2 road
构造出一个原图和一个各边方向相反的反图。先在反图上从终点开始进行一遍DFS,标记出可以到达终点的点,再标记出路径上不能包含(即存在一个与其相邻的节点不能到达终点)的节点,然后SPFA即可。
代码:
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
inline int read() {
int res = 0; bool bo = 0; char c;
while (((c = getchar()) < '0' || c > '9') && c != '-');
if (c == '-') bo = 1; else res = c - 48;
while ((c = getchar()) >= '0' && c <= '9')
res = (res << 3) + (res << 1) + (c - 48);
return bo ? ~res + 1 : res;
}
const int N = 1e4 + 5, M = 2e5 + 5, INF = 0x3f3f3f3f;
int n, m, ecnt, nxt[M], adj[N], go[M], ecnt2, nxt2[M], adj2[N], go2[M],
que[M << 2], len, dis[N], S, T; bool vis[N], con[N], can[N];
void add_edge(int u, int v) {
nxt[++ecnt] = adj[u]; adj[u] = ecnt; go[ecnt] = v;
nxt2[++ecnt2] = adj2[v]; adj2[v] = ecnt2; go2[ecnt2] = u;
}
void dfs(int u) {
can[u] = 1;
for (int e = adj2[u], v; e; e = nxt2[e])
if (!can[v = go2[e]]) dfs(v);
}
void mark() {
memset(con, true, sizeof(con));
int i; for (i = 1; i <= n; i++) for (int e = adj[i]; e; e = nxt[e])
if (!can[go[e]]) {con[i] = 0; break;}
}
int spfa() {
if (!con[S]) return -1;
int i; memset(dis, INF, sizeof(dis));
dis[que[len = 1] = S] = 0;
for (i = 1; i <= len; i++) {
int u = que[i]; vis[u] = 0;
for (int e = adj[u], v; e; e = nxt[e])
if (con[v = go[e]] && dis[u] + 1 < dis[v]) {
dis[v] = dis[u] + 1;
if (!vis[v]) vis[que[++len] = v] = 1;
}
}
return dis[T] < INF ? dis[T] : -1;
}
int main() {
//freopen("road.in", "r", stdin);
//freopen("road.out", "w", stdout);
int i, x, y; n = read(); m = read();
for (i = 1; i <= m; i++) x = read(), y = read(),
add_edge(x, y); S = read(); T = read();
printf("%d\n", (dfs(T), mark(), spfa()));
return 0;
}
T3 equation
首先,考虑怎样解决高精度计算的复杂度问题。
可以想到取模。选p(
考虑继续优化。可以发现,对于任意整数a,x,在模b意义下,自变量为
复杂度O(n∑b+mp)。∑b为选取的质数之和。
代码:
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
inline int read() {
int res = 0; bool bo = 0; char c;
while (((c = getchar()) < '0' || c > '9') && c != '-');
if (c == '-') bo = 1; else res = c - 48;
while ((c = getchar()) >= '0' && c <= '9')
res = (res << 3) + (res << 1) + (c - 48);
return bo ? ~res + 1 : res;
}
const int N = 105, M = 1e4 + 5, MOD = 5e4 + 5;
int PYZ[] = {10007, 25933, 27367, 38501, 41177}, n, m, val[N][7],
sol[7][MOD];
char s[M];
int ModPYZ(int len, int pyz) {
int i = 1 + (s[1] == '-'), ans = 0;
for (; i <= len; i++) ans = (ans * 10 + s[i] - '0') % pyz;
if (s[1] == '-') ans = pyz - ans; if (ans == pyz) ans = 0;
return ans;
}
int solve(int x, int id) {
int i, now = 1, ans = 0;
for (i = 0; i <= n; i++, (now *= x) %= PYZ[id])
(ans += val[i][id] * now) %= PYZ[id];
return ans;
}
int main() {
//freopen("equation.in", "r", stdin);
//freopen("equation.out", "w", stdout);
int i, j, l, cnt = 0; n = read(); m = read();
for (i = 0; i <= n; i++) {
scanf("%s", s + 1); l = strlen(s + 1);
for (j = 0; j < 5; j++) val[i][j] = ModPYZ(l, PYZ[j]);
}
for (i = 0; i < 5; i++) for (j = 0; j < PYZ[i]; j++)
sol[i][j] = solve(j, i);
for (i = 1; i <= m; i++) {
bool flag = 1; for (j = 0; j < 5; j++)
flag = flag && (sol[j][i % PYZ[j]] == 0);
if (flag) cnt++;
}
printf("%d\n", cnt);
for (i = 1; i <= m; i++) {
bool flag = 1; for (j = 0; j < 5; j++)
flag = flag && (sol[j][i % PYZ[j]] == 0);
if (flag) printf("%d\n", i);
}
return 0;
}