11.18 解题报告
总的来说没挂分,因为没啥分可以挂了。
预计得分 : 60 + 0 + 20 + 20
实际得分: 60 + 0 + 15 + 20
A
预计得分 : 60
实际得分: 60
写了 n^2 的暴力 + 特殊性质
特殊性质用暴力来写的,看了一下可以 \(\mathcal{O}(n)\) 推。
更正的代码:
想起来了,我没更正代码:
#include <bits/stdc++.h>
#define pb push_back
#define lson rt << 1
#define rson rt << 1 | 1
using namespace std;
typedef long long ll;
const int N = 1e6 + 10;
const int INF = 0x3f3f3f3f;
inline int read() {
int res = 0, f = 0; char ch = getchar();
for(; !isdigit(ch); ch = getchar()) f |= (ch == '-');
for(; isdigit(ch); ch = getchar()) res = (res << 1) + (res << 3) + (ch - '0');
return f ? -res : res;
}
int n, a[N], b[N];
ll ans = 0, dp[N];
namespace Sub1 {
void Main() {
ll cur = 10, js = 5;
dp[1] = 0, dp[2] = 1, dp[3] = 4, dp[4] = 10;
for(int i = 5; i <= n; i++) dp[i] = dp[i - 1] + cur, cur = (cur + js), js++;
cout << dp[n] << '\n';
exit(0);
}
}
signed main() {
freopen("swap.in", "r", stdin);
freopen("swap.out", "w", stdout);
n = read();
for(int i = 1; i <= n; i++) b[i] = n - i + 1;
for(int i = 1; i <= n; i++) a[i] = read();
int f = 0;
for(int i = 1; i <= n; i++) f |= (a[i] != b[i]);
if(!f) Sub1::Main();
for(int i = 1; i <= n; i++) {
if(a[i] == i) continue;
int wz = 0;
for(int j = i + 1; j <= n; j++)
if(a[j] == i) { wz = j; break;}
for(int j = wz; j > i; j--) ans += abs(a[j] - a[j - 1]), swap(a[j], a[j - 1]);
}
cout << ans << '\n';
return 0;
}
/*
这是一个 1~n 的排列
就是转换成了给你一个序列,把他变成 1~n 的序列
每个位置该去哪已经固定了
那怎样能使代价最小呢/hsh
昨晚做了个一样的题,那个是 n^2 的做法
先写个 n^2 的暴力看看
写完暴力了,感觉就是对于前后差值绝对值的一段区间进行翻转?
好像是套个文艺平衡树就可以在 n log n 做完了
可惜我早忘了怎么写了 /hsh
看看特殊性质的分数怎么写吧
现在有 60 分
特殊性质是倒序排列的
可以 O(n) 推出来
3
3 2 1
4
4
4 3 2 1
10
5
5 4 3 2 1
20
6
6 5 4 3 2 1
35
7
7 6 5 4 3 2 1
56
8
8 7 6 5 4 3 2 1
84
3 4 5 6 7 8 9 10 11
0 1 4 10 20 35 56 84 120 165 220 + 286
1 3 4 6 10 15 21 28 + 36 + 45 + 55 + 66
4 + 5 + 6 + 7 + 8 + 9 + 10 + 11
*/
B
搜索太难写了,写了很长时间没草出来了。
#include <bits/stdc++.h>
#define pb push_back
#define lson rt << 1
#define rson rt << 1 | 1
using namespace std;
#define int long long
const int N = 1e6 + 10;
const int INF = 0x3f3f3f3f;
const int Mod = 998244353;
inline int read() {
int res = 0, f = 0; char ch = getchar();
for(; !isdigit(ch); ch = getchar()) f |= (ch == '-');
for(; isdigit(ch); ch = getchar()) res = (res << 1) + (res << 3) + (ch - '0');
return f ? -res : res;
}
/*
n = k 和 k <= 20 的话,感觉比较好写?
k = 20 的话就是暴力了吧
n = k 说明了只要能选到 1 位置就行了
于是特殊性质的题目就转换成了:
有 n 个数字,期望多少轮能选 1
n <= 500
先手摸几组算算吧/hsh
第一轮选1的期望+第二轮选1的期望+……+第n轮选1的期望就是答案
1/n * 1 + (n - 1) * 1 / (n - 1) * 2 +
感觉不是很好写啊,没学过数学期望 /hsh
*/
int n, k, a[N];
int fz, fm;
std::bitset <N> vis;
inline int gcd(int a, int b) {
return !b ? a : gcd(b, a % b);
}
inline void tf(int &a, int &b, int c, int d) {
if(!a || !b) { a = c, b = d; return;}
int FM = b * d, Fz = a * d + b * c;
a = Fz, b = FM;
int Gcd = gcd(a, b);
a /= Gcd, b /= Gcd;
}
inline int ksm(int a, int b) {
int res = 1;
while(b) {
if(b & 1) res = (res * a) % Mod;
a = (a * a) % Mod, b >>= 1;
} return res % Mod;
}
// Start: 10:35 Finish:
// 首先要知道这是第x轮把1拿走,然后只会造成 x / sum 的贡献
// 直接强行用分数来替换成整数做就行了吧
// 问题是找能到达的最近的棋子。
// 1 1 0 1 1 0
// 破环成链然后从左边找,从右边找就行了
// 我觉得应该是给了 dfs 15 分,whq 不能这么绝情/hsh
// 现在还有 1.5h 我还有2个题的暴力没有写啊/fn
// 不会写 dfs啊,看不懂样例
// 首先每一轮都会把一个棋子整没
// 所以搜索最多搜索 k 层
inline int get(int pos) {
int l = pos, r = pos;
for(int i = pos; i >= 1; i--)
if(vis[i]) { l = i; break;}
for(int i = pos; i <= 2 * n; i++)
if(vis[i]) { r = i; break;}
if(pos - l <= r - pos) return l;
else return r;
}
inline void cclear(int x) {
if(x >= 1 && x <= n) vis[x] = vis[x + n] = 0;
else vis[x] = vis[x - n] = 0;
}
inline void Cover(int x) {
if(x >= 1 && x <= n) vis[x] = vis[x + n] = 1;
else vis[x] = vis[x + n] = 1;
}
bool qwq[N];
// 写不出 T2 的期望爆搜了 /hsh
// 再写30min,写不出来就溜了/hsh
// 真的不会写啊,现在的得分情况最优是 60 + 0 + 0 + 20 还没过百啊 /hsh
// 光写一下 n = k 的部分分吧
// sb 才写,去写一下 T3 的20分
// 现在最优得分是 : 60 + 0 + 20 + 20 = 100 /jy
// mb 啥也不会写,出的题很好,就是我看不大懂题目/hsh
// md 光在写碎碎念了,题到是没写多少/hsh
// 40 分钟我先去理解一下题目吧
// 最后10分钟的时候我去收拾文件夹
inline void dfs(int step, int Sum, int pre) {
if(step == k + 1) {
tf(fz, fm, pre, Sum);
return;
}
for(int i = 1; i <= n; i++) {
int wz = get(i);
cclear(wz);
if(pre == 1) dfs(step + 1, Sum * n % Mod, pre * n % Mod);
else if(wz == 1) dfs(step + 1, Sum * n % Mod, 1);
else dfs(step + 1, Sum * n % Mod, pre);
Cover(wz);
}
}
signed main() {
freopen("game.in", "r", stdin);
freopen("game.out", "w", stdout);
n = read(), k = read();
for(int i = 1; i <= k; i++) a[i] = read(), vis[a[i]] = 1;
for(int i = 1; i <= n; i++) vis[i + n] = vis[i];
dfs(1, 1, 0);
cout << (fz * ksm(fm, Mod - 2)) % Mod;
putchar('\n');
return 0;
}
C
一个很难读懂题的题。
读了很长时间,猜了个意思,然后过了大样例就跑了。
#include <bits/stdc++.h>
#define pb push_back
#define lson rt << 1
#define rson rt << 1 | 1
using namespace std;
typedef long long ll;
const int N = 1e6 + 10;
const int INF = 0x3f3f3f3f;
const int Mod = 998244353;
inline int read() {
int res = 0, f = 0; char ch = getchar();
for(; !isdigit(ch); ch = getchar()) f |= (ch == '-');
for(; isdigit(ch); ch = getchar()) res = (res << 1) + (res << 3) + (ch - '0');
return f ? -res : res;
}
struct Edge { int v, nxt;} e[N];
ll ans = 0;
int n, type, head[N], num_edge = 0, siz[N], fa[N];
inline void add_edge(int u, int v) { e[++num_edge] = (Edge) { v, head[u]}, head[u] = num_edge;}
inline void dfs(int u, int Fa) {
fa[u] = Fa;
for(int i = head[u]; i; i = e[i].nxt) {
int v = e[i].v;
if(v == Fa) continue;
siz[u]++;
dfs(v, u);
}
}
struct qwq {
int a, b, c, d;
} p[N];
int stc[N], sc = 0;
int ans1, ans2 = 0;
int cnt[N];
namespace Sub2 {
void Main() {
for(register int b = 1; b <= n; b++) {
int a = fa[b];
for(register int i = head[a]; i; i = e[i].nxt) {
int c = e[i].v;
if(c == b || c == fa[a]) continue;
for(int j = head[b]; j; j = e[j].nxt) {
int d = e[j].v;
if(d == a) continue;
p[++ans] = (qwq) {a, b,c, d};
if(ans > Mod) ans -= Mod;
}
}
}
}
}
// 我再把这些满足条件的四元组去dfs,然后判断?
// 那这样有20分,好像可以过100了
// 有20分了/fn
bool Check(qwq a, qwq b) {
cnt[a.a] = 0, cnt[a.b] = 0, cnt[a.c] = 0, cnt[a.d] = 0, cnt[b.a] = 0, cnt[b.b] = 0, cnt[b.c] = 0, cnt[b.d] = 0;
cnt[a.a]++, cnt[a.b]++, cnt[a.c]++, cnt[a.d]++, cnt[b.a]++, cnt[b.b]++, cnt[b.c]++, cnt[b.d]++;
if(cnt[a.a] > 1 || cnt[a.b] > 1 || cnt[a.c] > 1 || cnt[a.d] > 1) return false;
if(cnt[b.a] > 1 || cnt[b.b] > 1 || cnt[b.c] > 1 || cnt[b.d] > 1) return false;
return true;
}
bool Judge() {
for(int i = 1; i <= sc; i++) {
for(int j = i + 1; j <= sc; j++) {
if(!Check(p[stc[i]], p[stc[j]]))return false;
}
}
return true;
}
inline void Dfs(int step) {
if(step == ans + 1) {
if(Judge()) {
ans1++, ans2 += sc;
if(ans1 > Mod) ans1 -= Mod;
if(ans2 > Mod) ans2 -= Mod;
}
return;
}
stc[++sc] = step;
Dfs(step + 1);
--sc;
Dfs(step + 1);
}
// /hsh
signed main() {
// return system("fc ex_tree2.out ans.out"), 0;
// freopen("tree.in", "r", stdin);
// freopen("tree.out", "w", stdout);
n = read(), type = read();
for(int i = 1; i <= n - 1; i++) {
int u = read(), v = read();
add_edge(u, v), add_edge(v, u);
}
dfs(1, 0);
Sub2::Main();
Dfs(1);
cout << ans1 % Mod << '\n';
if(type == 1) cout << ans2 % Mod << '\n';
return 0;
}
D
// Start:10:10 Finish: 10:28 Score:20pts
#include <bits/stdc++.h>
#define pb push_back
#define lson rt << 1
#define rson rt << 1 | 1
using namespace std;
const int N = 1e6 + 10;
const int INF = 0x3f3f3f3f;
inline int read() {
int res = 0, f = 0; char ch = getchar();
for(; !isdigit(ch); ch = getchar()) f |= (ch == '-');
for(; isdigit(ch); ch = getchar()) res = (res << 1) + (res << 3) + (ch - '0');
return f ? -res : res;
}
int dis[N];
struct Node { int v, nxt;} e[N];
int n, q, head[N], num_edge = 0, top[N], son[N], fa[N], siz[N], dep[N];
inline void add_edge(int u, int v) { e[++num_edge] = (Node) {v, head[u]}, head[u] = num_edge;}
inline void dfs1(int u, int Fa, int w) {
fa[u] = Fa, dep[u] = dep[Fa] + 1, siz[u] = 1, dis[u] = dis[Fa] + w;
for(int i = head[u]; i; i = e[i].nxt) {
int v = e[i].v;
if(v == Fa) continue;
dfs1(v, u, 1);
siz[u] += siz[v];
if(siz[son[u]] < siz[v]) son[u] = v;
}
}
inline void dfs2(int u, int tp) {
top[u] = tp;
if(son[u]) dfs2(son[u], tp);
for(int i = head[u]; i; i = e[i].nxt) {
int v = e[i].v;
if(v == fa[u] || v == son[u]) continue;
dfs2(v, v);
}
}
inline int LCA(int x, int y) {
while(top[x] ^ top[y]) {
if(dep[top[x]] < dep[top[y]]) swap(x, y);
x = fa[top[x]];
} return dep[x] < dep[y] ? x : y;
}
inline int Dis(int x, int y) {
int lca = LCA(x, y);
return dis[x] + dis[y] - (dis[lca] << 1);
}
signed main() {
// return system("fc ex_atree2.out ans.out"), 0;
freopen("atree.in", "r", stdin);
freopen("atree.out", "w", stdout);
n = read(), q = read();
for(int i = 1; i <= n - 1; i++) {
int u = read(), v = read();
add_edge(u, v), add_edge(v, u);
}
dfs1(1, 0, 0), dfs2(1, 0);
while(q--) {
int u = read(), v = read(), d = read();
int ans = 0;
for(int i = 1; i <= n; i++) {
ans += (Dis(u, i) <= d || Dis(v, i) <= d);
}
cout << ans, putchar('\n');
}
return 0;
}