『模拟赛』多校A层冲刺NOIP2024模拟赛08
Rank
还行
A. 传送 (teleport)
签。
单源最短路,先想 Dijkstra。发现这道题还有个不同寻常的移动方式,可以以
被叫去整内务在楼梯上想到,一个点不应该来回走,于是想到若有
点击查看代码
#include<bits/stdc++.h>
#define fo(x, y, z) for(register int (x) = (y); (x) <= (z); (x)++)
#define fu(x, y, z) for(register int (x) = (y); (x) >= (z); (x)--)
using namespace std;
typedef long long ll;
#define lx ll
inline lx qr()
{
char ch = getchar();lx x = 0 , f = 1;
for(;ch<'0'||ch>'9';ch = getchar()) if(ch == '-') f = -1;
for(;ch>= '0' && ch<= '9';ch = getchar()) x = (x<<3) + (x<<1) + (ch^48);
return x*f;
}
#undef lx
#define qr qr()
#define pii pair<int, int>
#define M_P(a, b) make_pair(a, b)
#define fi first
#define se second
#define P_B(x) push_back(x)
const int Ratio = 0;
const int N = 2e5 + 5;
int n, m;
int hh[N], to[N << 3], ne[N << 3], w[N << 3], cnt;
ll dis[N];
bool yz[N];
struct rmm
{
ll dis; int u;
bool operator < (const rmm &a) const {return a.dis < dis;}
};
struct nd
{
int id, x, y;
} d[N], dd[N];
namespace Wisadel
{
void Wadd(int u, int v, int val)
{
to[++cnt] = v;
w[cnt] = val;
ne[cnt] = hh[u];
hh[u] = cnt;
}
void Wdij(int x)
{
priority_queue<rmm> q;
memset(dis, 0x3f, sizeof dis);
dis[x] = 0;
q.push({0, x});
while(q.size())
{
int u = q.top().u; q.pop();
if(yz[u]) continue;
yz[u] = 1;
for(int i = hh[u]; i != -1; i = ne[i])
{
int v = to[i];
if(dis[v] > dis[u] + w[i])
{
dis[v] = dis[u] + w[i];
q.push({dis[v], v});
}
}
}
}
short main()
{
freopen("teleport.in", "r", stdin) , freopen("teleport.out", "w", stdout);
// freopen(".err", "w", stderr);
n = qr, m = qr;
memset(hh, -1, sizeof hh);
fo(i, 1, n) dd[i].x = d[i].x = qr, dd[i].y = d[i].y = qr, d[i].id = dd[i].id = i;
sort(d + 1, d + 1 + n, [](nd a, nd b){return a.x < b.x;});
sort(dd + 1, dd + 1 + n, [](nd a, nd b){return a.y < b.y;});
fo(i, 1, n - 1)
{
int c1 = d[i + 1].x - d[i].x, c2 = dd[i + 1].y - dd[i].y;
Wadd(d[i].id, d[i + 1].id, c1), Wadd(d[i + 1].id, d[i].id, c1);
Wadd(dd[i].id, dd[i + 1].id, c2), Wadd(dd[i + 1].id, dd[i].id, c2);
}
fo(i, 1, m)
{
int a = qr, b = qr, c = qr;
Wadd(a, b, c), Wadd(b, a, c);
}
Wdij(1);
fo(i, 2, n) printf("%lld ", dis[i]);puts("");
return Ratio;
}
}
signed main(){return Wisadel::main();}
B. 排列 (permutation)
组合数学水题,状压 dp 也能做。
赛时发现不会插板法,于是选择分讨打表,但是到
发现只有
由于放不下赛时的做法,遂在正解中用了数据点分治。
点击查看代码
#include<bits/stdc++.h>
#define fo(x, y, z) for(register int (x) = (y); (x) <= (z); (x)++)
#define fu(x, y, z) for(register int (x) = (y); (x) >= (z); (x)--)
using namespace std;
typedef long long ll;
#define lx ll
inline lx qr()
{
char ch = getchar();lx x = 0 , f = 1;
for(;ch<'0'||ch>'9';ch = getchar()) if(ch == '-') f = -1;
for(;ch>= '0' && ch<= '9';ch = getchar()) x = (x<<3) + (x<<1) + (ch^48);
return x*f;
}
#undef lx
#define qr qr()
#define pii pair<int, int>
#define M_P(a, b) make_pair(a, b)
#define fi first
#define se second
#define P_B(x) push_back(x)
const int Ratio = 0;
const int N = 3e4 + 5, M = 3000;
const int mod = 998244353;
int n, k;
int a[N];
ll jc[N], ny[N];
namespace Wisadel
{
ll Wqp(ll x, int y)
{
ll res = 1;
while(y){if(y & 1) res = res * x % mod; x = x * x % mod; y >>= 1;}
return res;
}
ll Wc(int n, int m)
{
return jc[n] * ny[m] % mod * ny[n - m] % mod;
}
short main()
{
freopen("permutation.in", "r", stdin) , freopen("permutation.out", "w", stdout);
// freopen(".err", "w", stderr);
n = qr, k = qr;
jc[0] = ny[0] = 1;
fo(i, 1, n) jc[i] = jc[i - 1] * i % mod;
ny[n] = Wqp(jc[n], mod - 2);
fu(i, n - 1, 1) ny[i] = ny[i + 1] * (i + 1) % mod;
ll zc = n / k;
ll ans = 1;
if(zc <= 3) ans = jc[zc] * jc[n - zc] % mod * Wc(n - zc + 1, zc) % mod;
else if(zc <= 5)
{
ans = jc[zc] * jc[n - zc] % mod * Wc(n - zc + 1, zc) % mod;
ans = (ans + jc[zc - 1] * jc[n - zc] % mod * 2 * Wc(n - zc + 1, zc - 1) % mod) % mod;
}
else if(zc <= 7)
{
ans = jc[zc] * jc[n - zc] % mod * Wc(n - zc + 1, zc) % mod;
ans = (ans + jc[zc - 1] * jc[n - zc] % mod * 2 % mod * Wc(n - zc + 1, zc - 1) % mod * 4 % mod) % mod;
ans = (ans + jc[zc - 2] * jc[n - zc] % mod * 6 % mod * Wc(n - zc + 1, zc - 2) % mod) % mod;
ans = (ans + jc[zc - 2] * jc[n - zc] % mod * 4 % mod * Wc(n - zc + 1, zc - 2) % mod) % mod;
ans = (ans + jc[zc - 2] * jc[n - zc] % mod * 2 % mod * Wc(n - zc + 1, zc - 2) % mod * 2 % mod) % mod;
ans = (ans + jc[zc - 3] * jc[n - zc] % mod * 4 % mod * Wc(n - zc + 1, zc - 3) % mod) % mod;
}
else
{
ans = 0;
fo(i, 1, zc) a[i] = i;
do
{
int cnt = 0;
fo(i, 1, zc - 1) if(__gcd(a[i], a[i + 1]) == 1) cnt++;
ans = (ans + Wc(n - cnt, zc)) % mod;
} while(next_permutation(a + 1, a + 1 + zc));
ans = ans * jc[n - zc] % mod;
}
printf("%lld\n", ans);
return Ratio;
}
}
signed main(){return Wisadel::main();}
C. 战场模拟器 (simulator)
没学过势能线段树,不知道这样复杂度是正确的,遂没敢打,只打了 Subtask2 的 23pts。
发现这道题主要是死人不复活和护盾比较 ex,因此我们针对这两点直接暴力做就好。如果你打了 Subtask2,那么应该知道为什么要记录区间最小生命值及其数量,没打也能懂:因为每次扣血操作我们是暴力进行的,只有求濒死人数才用到最小值且只用到最小值。然后记录区间死亡人数,以及一个 lazy tag。我们发现,当区间没有盾并且打不死最小生命的英雄时我们没必要递归到单点做,因此再记录一个区间盾数量。
除了扣血,其它操作都是基本的线段树操作。在求濒死人数时还可以根据当前最小值是否
问题主要在证明这个做法的时间复杂度正确性,搜索发现并没有太好的讲解。于是只能感性理解:每个点的操作都是有上限的,在达到这个上限后便不用再进行单点修改,这样就保证了均摊复杂度。求复杂度好像用到了势能函数,不会,只给出结果:
来自丁真可能更好的复杂度分析:
点击查看代码
#include<bits/stdc++.h>
#define fo(x, y, z) for(register int (x) = (y); (x) <= (z); (x)++)
#define fu(x, y, z) for(register int (x) = (y); (x) >= (z); (x)--)
using namespace std;
typedef long long ll;
#define lx ll
inline lx qr()
{
char ch = getchar();lx x = 0 , f = 1;
for(;ch<'0'||ch>'9';ch = getchar()) if(ch == '-') f = -1;
for(;ch>= '0' && ch<= '9';ch = getchar()) x = (x<<3) + (x<<1) + (ch^48);
return x*f;
}
#undef lx
#define qr qr()
#define pii pair<int, int>
#define M_P(a, b) make_pair(a, b)
#define fi first
#define se second
#define P_B(x) push_back(x)
const int Ratio = 0;
const int N = 2e5 + 5, M = 3000;
const int mod = 998244353;
int n, m;
int a[N];
int a1[N << 2], dun[N << 2], num[N << 2];
ll s[N << 2], lazy[N << 2];
namespace Wisadel
{
#define ls (rt << 1)
#define rs (rt << 1 | 1)
#define mid ((l + r) >> 1)
void Wpushup(int rt)
{
a1[rt] = a1[ls] + a1[rs];
dun[rt] = dun[ls] + dun[rs];
s[rt] = min(s[ls], s[rs]);
num[rt] = 0;
if(s[ls] == s[rt]) num[rt] += num[ls];
if(s[rs] == s[rt]) num[rt] += num[rs];
}
void Wpushdown(int rt)
{
s[ls] += lazy[rt], s[rs] += lazy[rt];
lazy[ls] += lazy[rt], lazy[rs] += lazy[rt];
lazy[rt] = 0;
}
void Wbuild(int rt, int l, int r)
{
if(l == r)
{
s[rt] = a[l];
num[rt] = 1;
return ;
}
Wbuild(ls, l, mid), Wbuild(rs, mid + 1, r);
Wpushup(rt);
}
void Watk(int rt, int l, int r, int x, int y, int k)
{
if(x <= l && r <= y && s[rt] >= k && !dun[rt])
{
s[rt] -= k, lazy[rt] -= k;
return ;
}
if(l == r)
{
if(dun[rt]) dun[rt]--;
else a1[rt] = 1, num[rt] = 0, s[rt] = 4e18;
return ;
}
if(lazy[rt]) Wpushdown(rt);
if(x <= mid) Watk(ls, l, mid, x, y, k);
if(y > mid) Watk(rs, mid + 1, r, x, y, k);
Wpushup(rt);
}
void Wrec(int rt, int l, int r, int x, int y, int k)
{
if(x <= l && r <= y)
{
s[rt] += k, lazy[rt] += k;
return ;
}
if(lazy[rt]) Wpushdown(rt);
if(x <= mid) Wrec(ls, l, mid, x, y, k);
if(y > mid) Wrec(rs, mid + 1, r, x, y, k);
Wpushup(rt);
}
void Wdun(int rt, int l, int r, int x)
{
if(l == r)
{
dun[rt]++;
return ;
}
if(lazy[rt]) Wpushdown(rt);
if(x <= mid) Wdun(ls, l, mid, x);
else Wdun(rs, mid + 1, r, x);
Wpushup(rt);
}
int Wq1(int rt, int l, int r, int x, int y)
{
if(x <= l && r <= y) return a1[rt];
if(lazy[rt]) Wpushdown(rt);
int res = 0;
if(x <= mid) res += Wq1(ls, l, mid, x, y);
if(y > mid) res += Wq1(rs, mid + 1, r, x, y);
return res;
}
int Wq2(int rt, int l, int r, int x, int y)
{
if(s[rt]) return 0;
if(x <= l && r <= y) return num[rt];
if(lazy[rt]) Wpushdown(rt);
int res = 0;
if(x <= mid) res += Wq2(ls, l, mid ,x, y);
if(y > mid) res += Wq2(rs, mid + 1, r, x, y);
return res;
}
short main()
{
freopen("simulator.in", "r", stdin) , freopen("simulator.out", "w", stdout);
// freopen(".err", "w", stderr);
n = qr;
fo(i, 1, n) a[i] = qr;
Wbuild(1, 1, n);
m = qr;
fo(i, 1, m)
{
int op = qr, l = qr, r, k;
if(op == 1) r = qr, k = qr, Watk(1, 1, n, l, r, k);
else if(op == 2) r = qr, k = qr, Wrec(1, 1, n, l, r, k);
else if(op == 3) Wdun(1, 1, n, l);
else if(op == 4) r = qr, printf("%d\n", Wq1(1, 1, n, l, r));
else r = qr, printf("%d\n", Wq2(1, 1, n, l, r));
}
return Ratio;
}
}
signed main(){return Wisadel::main();}
D. 点亮 (light)
计数好题,咕咕咕。
代码十分好写。
末
在回了趟宿舍的干扰下打成这样感觉还行,甚至对 T1 起了正向帮助,那么______🤔🤔🤔
T2 属实是钻死胡同里去了,分讨了 2h+,策略失误,在纠正了数据点的问题后拿到 50pts,但没时间打 T3 了,想到的暴力做法就是正解却没打,血亏。
狂补组合数学。
完结撒花~
复活了。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探