『模拟赛』NOIP2024加赛8
Rank
唐
A. flandre
签。
比较显然,由于
说句闲话:四个核的虚拟机跑大样例要 1s 多,换成 DEV 或者本机 vscode 只用 0.3s。
点击查看代码
#include<bits/stdc++.h>
#define fo(x, y, z) for(int (x) = (y); (x) <= (z); (x)++)
#define fu(x, y, z) for(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 fi first
#define se second
#define pii pair<int, int>
#define P_B(x) push_back(x)
#define M_P(x, y) make_pair(x, y)
const int Ratio = 0;
const int N = 1e6 + 5;
int n, k;
int a[N], id[N];
ll ans;
int st[N], top;
namespace Wisadel
{
ll zc[N], zct;
inline void Wqw(ll x)
{
if(!x){putchar('0'); return ;}
while(x) zc[++zct] = x % 10, x /= 10;
while(zct) putchar(zc[zct--] + '0');
}
short main()
{
freopen("flandre.in", "r", stdin), freopen("flandre.out", "w", stdout);
n = qr, k = qr;
fo(i, 1, n) a[i] = qr, id[i] = i;
sort(id + 1, id + 1 + n, [](int A, int B){return a[A] > a[B];});
int tot = 0, nowtot = 0;
fo(i, 1, n)
{
if(i == 1) nowtot = 1;
else if(nowtot && a[id[i]] != a[st[top]]) tot += nowtot, nowtot = 1;
else if(nowtot && a[id[i]] == a[st[top]]) nowtot++;
ll zc = ans + 1ll * k * tot + a[id[i]];
if(zc >= ans) ans = zc, st[++top] = id[i];
else break;
}
Wqw(ans), putchar(' '), Wqw(top), puts("");
while(top) Wqw(st[top--]), putchar(' ');
puts("");
return Ratio;
}
}
signed main(){return Wisadel::main();}
B. meirin
这题没切纯唐了。
所求答案可以化成形如
发现单点求是没有前途的,我们考虑对一个区间求。如下图,我们求点
考虑枚举左侧的区间,那么其可以对应的是右侧所有区间,记录前缀和的前缀和,可以对每一个左侧区间
注意预处理时边界的处理。
点击查看代码
#include<bits/stdc++.h>
#define fo(x, y, z) for(int (x) = (y); (x) <= (z); (x)++)
#define fu(x, y, z) for(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 fi first
#define se second
#define pii pair<int, int>
#define P_B(x) push_back(x)
#define M_P(x, y) make_pair(x, y)
const int Ratio = 0;
const int N = 5e5 + 5;
const int mod = 1e9 + 7;
int n, q;
ll a[N], b[N];
ll v[N << 2], zz[N];
ll s[N], ss[N], h[N], hh[N];
namespace Wisadel
{
#define ls (rt << 1)
#define rs (rt << 1 | 1)
#define mid ((l + r) >> 1)
inline void Wpushup(int rt){v[rt] = (v[ls] + v[rs]) % mod;}
inline void Wbuild(int rt, int l, int r)
{
if(l == r)
{
v[rt] = zz[l];
return ;
}
Wbuild(ls, l, mid), Wbuild(rs, mid + 1, r);
Wpushup(rt);
}
inline ll Wq(int rt, int l, int r, int x, int y)
{
if(x <= l && r <= y) return v[rt];
ll res = 0;
if(x <= mid) res = (res + Wq(ls, l, mid, x, y)) % mod;
if(y > mid) res = (res + Wq(rs, mid + 1, r, x, y)) % mod;
return res;
}
short main()
{
freopen("meirin.in", "r", stdin), freopen("meirin.out", "w", stdout);
n = qr, q = qr;
fo(i, 1, n) a[i] = qr;
fo(i, 1, n) b[i] = qr;
fo(i, 1, n) s[i] = (s[i - 1] + a[i]) % mod;
fu(i, n, 1) h[i] = (h[i + 1] + a[i]) % mod;
fo(i, 1, n) ss[i] = (ss[i - 1] + s[i]) % mod;
fu(i, n, 1) hh[i] = (hh[i + 1] + h[i]) % mod;
ll ans = 0;
fo(i, 1, n)
{
ll zc = ((ss[n] - ss[i - 1] + mod) % mod - s[i - 1] * (n - i + 1) % mod + mod) % mod * i % mod;
zc = (zc + ((hh[1] - hh[i] + mod) % mod - h[i] * (i - 1) % mod + mod) % mod * (n - i + 1) % mod) % mod;
zz[i] = zc;
ans = (ans + zz[i] * b[i] % mod) % mod;
}
Wbuild(1, 1, n);
fo(i, 1, q)
{
int l = qr, r = qr; ll k = (qr % mod + mod) % mod;
ll zc = Wq(1, 1, n, l, r) * k % mod;
ans = (ans + zc) % mod;
printf("%lld\n", ans);
}
return Ratio;
}
}
signed main(){return Wisadel::main();}
C. sakuya
比较诈骗,赛时题面把大家都吓住了。
考虑期望的本质是所有方案代价的平均数,我们对于每条边统计其贡献,求和之后除以方案数即可。对于每一条边,考虑统计其代价的充要条件是在其连接的两个连通块中,各存在一个特殊点且要求二者在序列中相邻。那么设其中一端的子树内有
考虑加入修改如何做。将上述边贡献中
点击查看代码
#include<bits/stdc++.h>
#define fo(x, y, z) for(int (x) = (y); (x) <= (z); (x)++)
#define fu(x, y, z) for(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 fi first
#define se second
#define pii pair<int, int>
#define P_B(x) push_back(x)
#define M_P(x, y) make_pair(x, y)
const int Ratio = 0;
const int N = 5e5 + 5;
const int mod = 998244353;
int n, m, q;
int b[N], siz[N];
int hh[N], to[N << 1], ne[N << 1], cnt = 1;
ll qzs[N << 1], f[N], ans, jc[N];
namespace Wisadel
{
inline 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;
}
inline void Wadd(int u, int v, ll val)
{
to[++cnt] = v;
qzs[cnt] = val;
ne[cnt] = hh[u];
hh[u] = cnt;
}
inline void Wdfs(int u, int fa)
{
siz[u] = b[u];
for(int i = hh[u]; i != -1; i = ne[i])
{
int v = to[i];
if(v == fa) continue;
Wdfs(v, u);
siz[u] += siz[v];
ll zc = 2ll * siz[v] * (m - siz[v]) % mod * (m - 1) % mod * jc[m - 2] % mod;
f[u] = (f[u] + zc) % mod, f[v] = (f[v] + zc) % mod;
ans = (ans + zc * qzs[i] % mod) % mod;
}
}
short main()
{
freopen("sakuya.in", "r", stdin), freopen("sakuya.out", "w", stdout);
n = qr, m = qr;
jc[0] = 1; fo(i, 1, m) jc[i] = jc[i - 1] * i % mod;
memset(hh, -1, sizeof hh);
fo(i, 1, n - 1)
{
int a = qr, b = qr; ll c = qr;
Wadd(a, b, c), Wadd(b, a, c);
}
fo(i, 1, m) b[qr] = 1;
Wdfs(1, 0);
q = qr;
fo(i, 1, q)
{
int x = qr; ll k = qr;
ans = (ans + f[x] * k % mod) % mod;
printf("%lld\n", ans * Wqp(jc[m], mod - 2) % mod);
}
return Ratio;
}
}
signed main(){return Wisadel::main();}
D. 红楼 ~ Eastern Dream
容易发现模数和区间修改的段数有关,模数越大段数越小。首先考虑根号分治。对于小于
对于大于
发现修改和查询复杂度比例为
点击查看代码
#include<bits/stdc++.h>
#define fo(x, y, z) for(int (x) = (y); (x) <= (z); (x)++)
#define fu(x, y, z) for(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 fi first
#define se second
#define pii pair<int, int>
#define P_B(x) push_back(x)
#define M_P(x, y) make_pair(x, y)
const int Ratio = 0;
const int N = 2e5 + 5, NN = 450;
int n, m;
int a[N];
int bl[N], ed[N], sq;
ll s1[N], s2[N], lazy, f[NN][NN], c[N];
namespace Wisadel
{
inline void Wupd(int x, ll k)
{
int zc = bl[x];
c[x] += k, s1[zc] += k, s2[zc] += k * (ed[zc] - x + 1);
}
inline ll Wq(int l, int r)
{
ll res = 0;
fo(i, 1, bl[l] - 1) res += s1[i] * (r - l + 1);
fo(i, ed[bl[l] - 1] + 1, l - 1) res += c[i] * (r - l + 1);
if(bl[r] - bl[l] <= 1)
{
fo(i, l, r) res += c[i] * (r - i + 1);
}
else
{
fo(i, l, ed[bl[l]]) res += c[i] * (r - i + 1);
fo(i, bl[l] + 1, bl[r] - 1) res += s1[i] * (r - ed[i]) + s2[i];
fo(i, ed[bl[r] - 1] + 1, r) res += c[i] * (r - i + 1);
}
return res;
}
short main()
{
freopen("scarlet.in", "r", stdin), freopen("scarlet.out", "w", stdout);
n = qr, m = qr;
fo(i, 1, n) a[i] = qr, c[i] = a[i] - a[i - 1];
sq = sqrt(n);
fo(i, 1, sq) ed[i] = n / sq * i;
ed[sq] = n;
fo(i, 1, sq) fo(j, ed[i - 1] + 1, ed[i]) bl[j] = i, s1[i] += c[j], s2[i] += 1ll * c[j] * (ed[i] - j + 1);
fo(i, 1, m)
{
int op = qr, l = qr, r = qr; ll k;
if(op == 1)
{
k = qr;
if(l <= r + 1) lazy += k;
else if(l < sq)
{
ll zc = 0;
fo(j, 0, r) zc += k, f[l][j] += zc;
fo(j, r + 1, l - 1) f[l][j] += zc;
}
else
{
for(int j = 0; j < n; j += l)
{
Wupd(j + 1, k);
if(j + 1 + r + 1 <= n) Wupd(j + 2 + r, -k);
}
}
}
else
{
ll ans = lazy * (r - l + 1);
fo(j, 1, sq - 1)
{
int tim = ((r - 1) / j) - ((l + j - 1) / j);
if(tim > 0) ans += f[j][j - 1] * tim;
int L = (l - 1 + j) % j, R = (r - 1 + j) % j;
if((r - 1) / j == (l - 1) / j) ans -= f[j][j - 1];
ans += f[j][j - 1] - (L ? f[j][L - 1] : 0) + f[j][R];
}
ans += Wq(l, r);
printf("%lld\n", ans);
}
}
return Ratio;
}
}
signed main(){return Wisadel::main();}
末
赛时状态一般,T2 一直没往区间和上想属实是唐了。T3 被题面吓到没敢深究,T4 打的暴力喜提 70pts。
NOIP 这样的状态真就 G 了。考前打这样一场模拟赛也算是长教训。研究题不能只在一个方向上搞。点不行想线,线要再扩展到面。全面地研究每道题,才能得出真正优的解法。
以及细节处理上,T1 上来就打,越打越发现有些东西没处理,然后改来改去错失首 A。好在这只是签,码短好调,如果在一道码力题上犯这样的错,可能错失的就是 100pts 了。Think twice, code once.
还剩一场终结赛,全力以赴,打出气势。
完结撒花~
~
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探