CSP-S 20
9.11
今天是挂分的好日子~~~
101=0+10+91
t1 追逐游戏 (chase)
倍增+k祖先
算了不想写了.......
第2次没保存然后死机丢失了...
不难理解也不难实现,细节手模即可。
t1 就这样吧,看代码。
code
点击查看代码
#include <bits/stdc++.h>
using namespace std;
const int N = 2e5 + 10;
int n, q;
vector<int> e[N];
int fa[N][20], dep[N];
void dfs1(int x, int f)
{
fa[x][0] = f;
dep[x] = dep[f] + 1;
for (int i = 1; i <= 19; ++i)
fa[x][i] = fa[fa[x][i - 1]][i - 1];
for (auto y : e[x])
if (y != f)
dfs1(y, x);
}
int LCA(int x, int y)
{
if (dep[x] < dep[y])
swap(x, y);
for (int i = 19; ~i; --i)
if (dep[fa[x][i]] >= dep[y])
x = fa[x][i];
if (x == y)
return x;
for (int i = 19; ~i; --i)
if (fa[x][i] != fa[y][i])
x = fa[x][i], y = fa[y][i];
return fa[x][0];
}
inline int get_dis(int x, int y)
{
int lca = LCA(x, y);
return dep[x] + dep[y] - 2 * dep[lca];
}
inline int jump_k(int x, int k)
{
for (int i = 19; ~i; --i) //~i --> i>=0!!!!!!!
if (k & (1 << i))
x = fa[x][i];
return x;
}
inline void solve(int x, int y)
{
int dis = get_dis(x, y);
int k = (dis + 1) >> 1;
cout << k << ' ';
if (dep[x] < dep[y])
swap(x, y), k = dis - k;
cout << jump_k(x, k) << "\n";
}
signed main()
{
freopen("chase.in", "r", stdin);
freopen("chase.out", "w", stdout);
ios::sync_with_stdio(0);
cin.tie(0);
cin >> n >> q;
for (int i = 1, u, v; i < n; ++i)
{
cin >> u >> v;
e[u].push_back(v);
e[v].push_back(u);
}
dfs1(1, 0);
int s1, t, s2;
while (q--)
{
cin >> s1 >> t >> s2;
int dis1 = get_dis(s1, t);
int dis2 = get_dis(s2, t);
if (dis1 < dis2)
cout << dis2 << ' ' << t << "\n";
else
solve(s1, s2);
}
return 0;
}
t2 统计
赛时用memset挂了20pts...
正解巧妙。
类似异或哈希做法。
具体的:
对于 \(1\) 到 \(m-1\) 中每个数随机一个哈希值,令 \(v_m=-\sum_{i=1}^{m-1}v_i\)
这样做可使满足要求的区间 \(l,r\) 的 \(sum_r-sum_{l-1}\) 为0.
考虑快速统计答案:
将 \(sum\) 升序排列,之后快速统计。
“快速统计”部分看代码理解(语文功底太差导致的)。
code
点击查看代码
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 1e6 + 10;
int T;
int n, m;
int a[N], sum[N], v[N];
mt19937_64 myrand(time(0));
signed main()
{
freopen("st.in", "r", stdin);
freopen("st.out", "w", stdout);
ios::sync_with_stdio(0);
cin.tie(0);
cin >> T;
while (T--)
{
cin >> n >> m;
for (int i = 0; i <= n; ++i)
sum[i] = 0, v[i] = 0;
for (int i = 1; i < m; ++i)
v[i] = myrand(), v[m] -= v[i];
for (int i = 1; i <= n; ++i)
cin >> a[i], sum[i] = sum[i - 1] + v[a[i]];
sort(sum, sum + 1 + n); // 注意必须手动保证sum[0]为0!!!
int cnt = 1, ans = 0;
for (int i = 1; i <= n; ++i)
{
if (sum[i] != sum[i - 1])
cnt = 0;
ans += cnt++;
}
cout << ans << "\n";
}
return 0;
}
t3 软件工程
抽象东西假贪心有 96pts!!?
假做法:
code
点击查看代码
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 1e5 + 10;
const int inf = 1e9 + 7;
int n, k;
bool flag[N];
struct node
{
int l, r, id;
} a[N], b[N];
inline bool cmp1(node a, node b) { return a.l < b.l; }
inline bool cmp2(node a, node b) { return a.l > b.l; }
signed main()
{
freopen("se.in", "r", stdin);
freopen("se.out", "w", stdout);
ios::sync_with_stdio(0);
cin.tie(0);
cin >> n >> k;
for (int i = 1; i <= n; ++i)
{
cin >> a[i].l >> a[i].r;
a[i].id = i;
b[i].l = a[i].r - a[i].l, b[i].r = i;
}
int ans = 0;
if (k >= n)
{
for (int i = 1; i <= n; ++i)
ans += a[i].r - a[i].l;
cout << ans << "\n";
return 0;
}
sort(a + 1, a + 1 + n, cmp1);
sort(b + 1, b + 1 + n, cmp2);
for (int i = 1; i <= k - 1; ++i)
ans += b[i].l, flag[b[i].r] = 1;
int l = 0, r = inf;
for (int i = 1; i <= n; ++i)
{
if (flag[a[i].id])
continue;
l = max(l, a[i].l), r = min(r, a[i].r);
}
if (l < r)
ans += r - l;
memset(flag, 0, sizeof(flag));//下面几乎一样的部分你可以理解成针对hack的特判
int maxn = 0, dat1 = 0, dat2 = 0;
// for (int i = 1; i <= n; ++i)
// cerr << a[i].l << ' ' << a[i].r << "\n";
for (int i = 1; i < n; ++i)
{
if (min(a[i].r, a[i + 1].r) - a[i + 1].l > maxn)
maxn = min(a[i].r, a[i + 1].r) - a[i + 1].l, dat1 = a[i].id, dat2 = a[i + 1].id;
}
int ans2 = maxn;
// cerr << dat1 << ' ' << dat2 << "\n";
flag[dat1] = flag[dat2] = 1;
for (int i = 1; i <= min(k - 2, n); ++i)
{
if (flag[i])
continue;
ans2 += b[i].l, flag[b[i].r] = 1;
}
l = 0, r = 1e9;
for (int i = 1; i <= n; ++i)
{
if (flag[a[i].id])
continue;
l = max(l, a[i].l), r = min(r, a[i].r);
}
// cerr << l << ' ' << r << "\n";
// cerr << ans2 << "\n";
if (l < r)
ans2 += r - l;
cout << max(ans,ans2) << '\n';
return 0;
}
至于真的:
咕
t4 命运的X
咕
看看题解说的:

本文来自博客园,作者:HS_fu3,转载请注明原文链接:https://www.cnblogs.com/HS-fu3/p/19153724

浙公网安备 33010602011771号