[赛记] 多校A层冲刺NOIP2024模拟赛15
追逐游戏 (chase) 50pts
比较卡常;
考虑二分答案,发现我们只需要在知道答案的情况下找出终点即可,所以用倍增找出终点,最后判断一下合不合法即可;
时间复杂度:
当然也可以分讨做到
点击查看代码
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
int n, q;
struct sss{
int t, ne;
}e[500005];
int h[500005], cnt;
inline void add(int u, int v) {
e[++cnt].t = v;
e[cnt].ne = h[u];
h[u] = cnt;
}
#define FI(n) FastIO::read(n)
#define FO(n) FastIO::write(n)
#define Flush FastIO::Fflush()
namespace FastIO {
const int SIZE = 1 << 16;
char buf[SIZE], obuf[SIZE], str[60];
int bi = SIZE, bn = SIZE, opt;
inline int read(register char *s) {
while(bn) {
for (; bi < bn && buf[bi] <= ' '; bi = -~bi);
if (bi < bn) break;
bn = fread(buf, 1, SIZE, stdin);
bi &= 0;
}
register int sn=0;
while(bn) {
for (; bi < bn && buf[bi] > ' '; bi = -~bi) s[sn++] = buf[bi];
if(bi < bn) break;
bn = fread(buf,1,SIZE,stdin);
bi &= 0;
}
s[sn] &= 0;
return sn;
}
inline bool read(register int &x){
int n = read(str), bf = 0;
if(!n) return 0;
register int i=0;
(str[i] == '-') && (bf = 1, i = -~i);
(str[i] == '+') && (i = -~i);
for (x = 0; i < n; i = -~i) x = (x << 3) + (x << 1) + (str[i] ^ 48);
bf && (x = ~x + 1);
return 1;
}
inline bool read(register long long &x) {
int n = read(str), bf = 1;
if(!n) return 0;
register int i=0;
(str[i] == '-') && (bf = -1,i = -~i);
for (x = 0; i < n; i= -~i) x = (x << 3) + (x << 1) + (str[i] ^ 48);
(bf < 0) && (x = ~x + 1);
return 1;
}
inline void write(register int x) {
if(!x) obuf[opt++] = '0';
else {
(x < 0) && (obuf[opt++] = '-', x = ~x + 1);
register int sn = 0;
while(x) str[sn++] = x % 10 + '0', x /= 10;
for (register int i = sn - 1; i >= 0; i = ~-i) obuf[opt++] = str[i];
}
(opt >= (SIZE >> 1)) && (fwrite(obuf, 1, opt, stdout), opt &= 0);
}
inline void write(register long long x) {
if(!x) obuf[opt++] = '0';
else {
(x < 0) && (obuf[opt++] = '-', x = ~x + 1);
register int sn = 0;
while(x) str[sn++] = x % 10 + '0', x /= 10;
for (register int i = sn - 1; i >= 0; i = ~-i) obuf[opt++] = str[i];
}
(opt >= (SIZE >> 1)) && (fwrite(obuf, 1, opt, stdout), opt &= 0);
}
inline void write(register unsigned long long x){
if(!x) obuf[opt++] = '0';
else {
register int sn=0;
while(x) str[sn++] = x % 10 + '0', x /= 10;
for (register int i = sn - 1 ; i >= 0 ; i = ~-i)obuf[opt++] = str[i];
}
(opt >= (SIZE >> 1)) && (fwrite(obuf, 1, opt, stdout), opt &= 0);
}
inline void write(register char x) {
obuf[opt++] = x;
(opt >= (SIZE >> 1)) && (fwrite(obuf, 1, opt, stdout), opt &= 0);
}
inline void Fflush(){
opt && fwrite(obuf, 1, opt, stdout);
opt &= 0;
}
}
int f[200005][25], dep[500005], dfn[500005], dcnt, ff[500005], st[200005][25];
void dfs(int x, int fa) {
dep[x] = dep[fa] + 1;
dfn[x] = ++dcnt;
st[dfn[x]][0] = x;
f[x][0] = fa;
ff[x] = fa;
for (int i = h[x]; i; i = e[i].ne) {
int u = e[i].t;
if (u == fa) continue;
dfs(u, x);
}
}
int p[25];
inline int get(int x,int y){
return dep[x] < dep[y] ? x : y;
}
inline int lca(int x, int y){
if(x == y) return x;
if((x = dfn[x]) > (y = dfn[y])) swap(x, y);
int k = __lg(y - x++);
return ff[get(st[x][k], st[y - (1 << k) + 1][k])];
}
inline bool cck(int s, int t, int x) {
return ((dep[s] + dep[t] - 2 * dep[lca(s, t)]) <= x);
}
inline pair<bool, int> ck(int s, int t, int ss, int lc, int sum, int su, int x) {
int to = 0;
int xx = x;
if (x <= su) {
for (int j = 17; j >= 0; j--) {
if (p[j] > x) continue;
if (dep[f[s][j]] < dep[lc]) continue;
s = f[s][j];
x -= p[j];
}
} else {
x -= su;
s = lc;
}
if (!x) {
to = s;
return {cck(to, ss, xx), to};
} else {
if (sum <= x) {
to = t;
return {cck(to, ss, xx), to};
} else {
sum -= x;
for (int j = 17; j >= 0; j--) {
if (dep[f[t][j]] < dep[lc]) continue;
if (p[j] > sum) continue;
t = f[t][j];
sum -= p[j];
}
to = t;
return {cck(to, ss, xx), to};
}
}
}
int main() {
freopen("chase.in", "r", stdin);
freopen("chase.out", "w", stdout);
FI(n); FI(q);
int x, y;
for (int i = 1; i <= n - 1; i++) {
FI(x); FI(y);
add(x, y);
add(y, x);
}
dfs(1, 0);
p[0] = 1;
for (int j = 1; j <= 17; j++) {
p[j] = p[j - 1] * 2;
for (int i = 1; i + (1 << (j - 1)) <= n; i++) {
st[i][j] = get(st[i + (1 << (j - 1))][j - 1], st[i][j - 1]);
}
for (int i = 1; i <= n; i++) {
f[i][j] = f[f[i][j - 1]][j - 1];
}
}
int z;
for (int i = 1; i <= q; i++) {
FI(x);
FI(y);
FI(z);
int l = 0;
int r = n - 1;
int ans = 0, an = 0;
int sum = 0, su = 0;
int tt = y;
int xx = x;
int lc = lca(x, y);
for (int j = 17; j >= 0; j--) {
if (dep[f[tt][j]] < dep[lc]) continue;
tt = f[tt][j];
sum += p[j];
}
for (int j = 17; j >= 0; j--) {
if (dep[f[xx][j]] < dep[lc]) continue;
xx = f[xx][j];
su += p[j];
}
while(l <= r) {
int mid = (l + r) >> 1;
pair<bool, int> pi = ck(x, y, z, lc, sum, su, mid);
if (pi.first) {
r = mid - 1;
ans = mid;
an = pi.second;
} else l = mid + 1;
}
FO(ans); FO(' '); FO(an); FO('\n');
}
Flush;
return 0;
}
统计 30pts
线段树暴力30pts;
用Hash乱搞搞就对了。。。
把
时间复杂度:
点击查看代码
#include <iostream>
#include <cstdio>
#include <random>
#include <ctime>
#include <algorithm>
using namespace std;
mt19937_64 ran(time(0));
int t;
int n, m;
long long x[1000005];
unsigned long long mp[1000005], sum[1000005], a[1000005];
long long ans;
int main() {
freopen("st.in", "r", stdin);
freopen("st.out", "w", stdout);
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin >> t;
while(t--) {
cin >> n >> m;
ans = 0;
for (int i = 1; i <= n; i++) {
cin >> x[i];
if (!mp[x[i]] && x[i] != m) mp[x[i]] = ran();
}
unsigned long long su = 0;
for (int i = 1; i <= m - 1; i++) {
su += mp[i];
}
mp[m] = -su;
for (int i = 1; i <= n; i++) {
a[i] = mp[x[i]];
}
for (int i = 1; i <= n; i++) sum[i] = sum[i - 1] + a[i];
sort(sum + 1, sum + 1 + n);
long long summ = 1;
for (int i = 1; i <= n; i++) {
if (sum[i] != sum[i - 1]) {
ans += (summ * (summ - 1)) / 2;
summ = 1;
} else summ++;
}
ans += (summ * (summ - 1)) / 2;
cout << ans << '\n';
for (int i = 1; i <= m; i++) mp[i] = 0;
}
return 0;
}
软件工程 21pts
直接暴搜21pts;
正解考虑DP,发现完全包含一个区间的区间要么不选,要么单独成一个,所以把这些删除以后DP;
分两种情况:有不交的区间,没有不交的区间;
前者直接输出前
最后前缀
点击查看代码
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <vector>
using namespace std;
int n, k;
struct sss{
long long l, r;
bool operator <(const sss &A) const {
if (l == A.l) return r > A.r;
else return l < A.l;
}
}e[50005], c[50005];
bool cmp(sss x, sss y) {
return (x.r - x.l) > (y.r - y.l);
}
vector<long long> v;
long long sum[50005];
int cnt;
long long f[5005][5005];
namespace SEG{
inline int ls(int x) {
return x << 1;
}
inline int rs(int x) {
return x << 1 | 1;
}
struct sss{
int l, r, mi;
}tr[8000005];
inline void push_up(int id) {
tr[id].mi = min(tr[ls(id)].mi, tr[rs(id)].mi);
}
void bt(int id, int l, int r) {
tr[id].l = l;
tr[id].r = r;
tr[id].mi = 0x3f3f3f3f;
if (l == r) return;
int mid = (l + r) >> 1;
bt(ls(id), l, mid);
bt(rs(id), mid + 1, r);
}
void add(int id, int pos, int d) {
if (tr[id].l == tr[id].r) {
tr[id].mi = min(tr[id].mi, d);
return;
}
int mid = (tr[id].l + tr[id].r) >> 1;
if (pos <= mid) add(ls(id), pos, d);
else add(rs(id), pos, d);
push_up(id);
}
int ask(int id, int l, int r) {
if (tr[id].l >= l && tr[id].r <= r) return tr[id].mi;
int mid = (tr[id].l + tr[id].r) >> 1;
if (r <= mid) return ask(ls(id), l, r);
else if (l > mid) return ask(rs(id), l, r);
else return min(ask(ls(id), l, mid), ask(rs(id), mid + 1, r));
}
}
long long w() {
sort(e + 1, e + 1 + n, cmp);
long long ans = 0;
for (int i = 1; i <= k - 1; i++) {
ans += (e[i].r - e[i].l);
}
return ans;
}
long long maa[50005];
bool vis[50005];
int main() {
freopen("se.in", "r", stdin);
freopen("se.out", "w", stdout);
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin >> n >> k;
long long ma = 0;
for (int i = 1; i <= n; i++) {
cin >> e[i].l >> e[i].r;
ma = max(ma, e[i].l);
}
sort(e + 1, e + 1 + n);
SEG::bt(1, 1, ma);
for (int i = n; i >= 1; i--) {
int r = SEG::ask(1, e[i].l, e[i].r);
if (r >= e[i].l && r <= e[i].r) vis[i] = true;
SEG::add(1, e[i].l, e[i].r);
}
for (int i = 1; i <= n; i++) {
if (!vis[i]) c[++cnt] = e[i];
else v.push_back(e[i].r - e[i].l);
}
sort(v.begin(), v.end(), greater<long long>());
for (int i = 0; i < v.size(); i++) {
sum[i + 1] = sum[i] + v[i];
}
maa[0] = c[1].r;
for (int i = 1; i <= cnt; i++) {
for (int j = 1; j <= min(i, k); j++) {
f[i][j] = max(f[i][j], maa[j - 1] - c[i].l);
}
for (int j = 1; j <= min(i, k); j++) {
maa[j] = max(maa[j], f[i][j] + c[i + 1].r);
}
}
long long ans = 0;
for (int i = 1; i <= k; i++) {
ans = max(ans, f[cnt][i] + sum[k - i]);
}
cout << max(ans, w());
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】