[赛记] NOIP2024加赛8
大抵是NOIP前写的最后一篇题解了吧。。。
flandre 80pts
赛时打的错解A了,然后证伪以后写了个更错的错解80pts;
考虑我们最终要求的答案是
考虑怎样证明这个结论,感性理解一下就是尽量选大的然后挺对;
考虑比较严谨的证明;
如果序列中没有重复的元素,那么正确性显而易见;
考虑如果有重复的元素怎么办;
假设现在我们选了一个可重集合
证毕;
然后上个
点击查看代码
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <vector>
using namespace std;
long long n, k;
struct sss{
long long a;
int id;
bool operator <(const sss &A) const {
return a < A.a;
}
}e[1000005];
vector<int> v;
namespace BIT{
inline int lowbit(int x) {
return x & (-x);
}
int tr[3000005];
inline void add(int pos, int d) {
for (int i = pos; i <= 3000000; i += lowbit(i)) tr[i] += d;
}
inline int ask(int d) {
int ans = 0;
for (int i = d; i; i -= lowbit(i)) ans += tr[i];
return ans;
}
}
int main() {
freopen("flandre.in", "r", stdin);
freopen("flandre.out", "w", stdout);
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin >> n >> k;
for (int i = 1; i <= n; i++) {
cin >> e[i].a;
e[i].id = i;
}
sort(e + 1, e + 1 + n);
long long ans = 0, sum = 0, now = 0;
for (int i = n; i >= 1; i--) {
now = now + k * (BIT::ask(3000000) - BIT::ask(e[i].a + 2000000)) + e[i].a;
if (now > ans) {
ans = now;
sum = i;
}
BIT::add(e[i].a + 2000000, 1);
}
if (!sum) {
cout << 0 << ' ' << 0;
return 0;
}
cout << ans << ' ' << n - sum + 1 << '\n';
for (int i = sum; i <= n; i++) cout << e[i].id << ' ';
return 0;
}
meirin 100pts
发现一个式子有四个
这个题的
发现我们最终求的是
设
先不考虑修改,那么考虑一个
简单来讲就是上一个的系数减去不包含这个点的系数(右端点是
发现前面两个
修改直接用这个区间的系数和乘要加的值然后和原来的答案相加即可,这个可以前缀和处理;
时间复杂度:
点击查看代码
#include <iostream>
#include <cstdio>
using namespace std;
const long long mod = 1000000007;
int n, q;
long long a[500005], b[500005], sum[500005], p[500005], val[500005], su[500005];
int main() {
freopen("meirin.in", "r", stdin);
freopen("meirin.out", "w", stdout);
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin >> n >> q;
for (int i = 1; i <= n; i++) {
cin >> a[i];
}
for (int i = 1; i <= n; i++) {
cin >> b[i];
}
sum[n] = a[n];
sum[n] = (sum[n] + mod) % mod;
for (int i = n - 1; i >= 1; i--) {
sum[i] = (sum[i + 1] + (a[i] * (n - (i + 1) + 1) % mod + a[i]) % mod) % mod;
sum[i] = (sum[i] + mod) % mod;
}
p[1] = a[1];
p[1] = (p[1] + mod) % mod;
for (int i = 2; i <= n; i++) {
p[i] = (p[i - 1] + ((a[i] * (i - 1)) % mod + a[i]) % mod) % mod;
p[i] = (p[i] + mod) % mod;
}
val[1] = sum[1];
long long ans = ((val[1] * b[1]) % mod + mod) % mod;
for (int i = 2; i <= n; i++) {
val[i] = ((sum[i] + val[i - 1]) % mod - p[i - 1]) % mod;
val[i] = (val[i] + mod) % mod;
ans = (ans + (val[i] * b[i]) % mod + mod) % mod;
}
for (int i = 1; i <= n; i++) {
su[i] = (su[i - 1] + val[i]) % mod;
}
int l, r;
long long k;
for (int i = 1; i <= q; i++) {
cin >> l >> r;
cin >> k;
long long now = ((su[r] - su[l - 1] + mod) % mod + mod) % mod;
ans = (ans + (now * k) % mod + mod) % mod;
cout << ans << '\n';
}
return 0;
}
sakuya 15pts
这种题有个套路:统计边被经过的次数;
钦定
设
考虑一条边
其中
然后就得到了每条边被经过的次数,这个可以
考虑修改,发现修改只是将与一个点相连的所有边的边权
最后不要忘了除以总方案数
时间复杂度:
点击查看代码
#include <iostream>
#include <cstdio>
using namespace std;
#define int long long
const long long mod = 998244353;
int n, m, q;
struct sss{
int t, ne;
long long w;
}e[1000005];
int h[1000005], cnt;
void add(int u, int v, long long ww) {
e[++cnt].t = v;
e[cnt].ne = h[u];
h[u] = cnt;
e[cnt].w = ww;
}
int f[500005];
long long a[500005], ans, inv, val;
bool vis[500005];
void afs(int x, int fa) {
if (vis[x]) f[x] = 1;
for (int i = h[x]; i; i = e[i].ne) {
int u = e[i].t;
if (u == fa) continue;
afs(u, x);
f[x] += f[u];
}
}
void dfs(int x, int fa) {
for (int i = h[x]; i; i = e[i].ne) {
int u = e[i].t;
if (u == fa) continue;
dfs(u, x);
a[x] = (a[x] + f[u] * (f[1] - f[u]) % mod * 2 % mod * val % mod) % mod;
a[u] = (a[u] + f[u] * (f[1] - f[u]) % mod * 2 % mod * val % mod) % mod;
ans = (ans + f[u] * (f[1] - f[u]) % mod * 2 % mod * val % mod * e[i].w % mod) % mod;
}
}
long long ksm(long long a, long long b) {
long long ans = 1;
while(b) {
if (b & 1) ans = ans * a % mod;
a = a * a % mod;
b >>= 1;
}
return ans;
}
signed main() {
freopen("sakuya.in", "r", stdin);
freopen("sakuya.out", "w", stdout);
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin >> n >> m;
int x, y;
long long w;
for (int i = 1; i <= n - 1; i++) {
cin >> x >> y;
cin >> w;
add(x, y, w);
add(y, x, w);
}
for (int i = 1; i <= m; i++) {
cin >> x;
vis[x] = true;
}
val = 1;
for (int i = 2; i <= m - 1; i++) val = val * i % mod;
inv = val * m % mod;
inv = ksm(inv, mod - 2);
afs(1, 0);
dfs(1, 0);
cin >> q;
long long k;
for (int i = 1; i <= q; i++) {
cin >> x >> k;
ans = (ans + a[x] * k % mod) % mod;
cout << ans * inv % mod << '\n';
}
return 0;
}
红楼 ~ Eastern Dream 65pts
赛时没写正解,一是不会,二是写出来常数也大,800ms很难卡过去;
看见部分分有
对于
对于
这个不能套线段树做,对于区间加,我们可以想到差分,考虑树状数组区间修改区间查询的做法,我们也可以维护一个差分数组
然后类似树状数组,我们维护
对于
然后我们修改时直接暴力
时间复杂度:
点击查看代码
#include <iostream>
#include <cstdio>
#include <cmath>
#include<bits/stdc++.h>
using namespace std;
namespace IO{
struct IO{
char buf[1<<16],*p1,*p2;
char pbuf[1<<16], *pp = pbuf;
#define gc() ((p1==p2&&(p2=((p1=buf)+fread_unlocked(buf,1,1<<16,stdin)),p1==p2))?EOF:*p1++)
#define pc putchar_unlocked
template<class T>
inline void read(T &x){
x = 0;bool flag = false;char s = gc();
for(;s < '0' || '9' < s;s = gc());
for(;'0' <= s && s <= '9';s = gc()) x = (x<<1)+(x<<3)+(s^48);
}
template<class T,class ...Args>
inline void read(T &x,Args&... argc){read(x);read(argc...);}
template <class T>
inline void write(T x) {
static int sta[30],top = 0;
do{sta[top++] = x % 10, x /= 10;}while(x);
while(top) pc(sta[--top] + '0');
}
inline void write(char x){pc(x);}
template <class T,class... Args>
inline void write(T x,Args... argc) {write(x);write(argc...);}
}io;
#define read io.read
#define write io.write
}using namespace IO;
int n, m;
long long f[455][455], a[500005], sum[500005];
int sq;
int st[455], ed[455], belog[500005];
long long c[500005], ci[500005], sc[455], sci[455];
inline long long w(long long l, long long r) {
long long ans = sum[r];
if (l > 0) ans -= sum[l - 1];
for (int i = 1; i <= sq; i++) {
long long L = l + (i - 1 - (l % i) + 1);
if (l % i == 0) L = l;
long long R = r - (r % i) - 1;
if (r % i == i - 1) R = r;
if (L > R) {
if ((r % i) - (l % i) == r - l) {
ans += f[i][r % i];
if ((l % i) > 0) ans -= f[i][(l % i) - 1];
} else {
ans += f[i][r % i];
ans += f[i][i - 1];
if ((l % i) > 0) ans -= f[i][(l % i) - 1];
}
continue;
}
ans += (R - L + 1) / i * f[i][i - 1];
if (R != r) ans += f[i][r % i];
if (L != l) ans += f[i][i - 1];
if ((l % i) > 0 && L != l) ans -= f[i][(l % i) - 1];
}
return ans;
}
int main() {
freopen("scarlet.in", "r", stdin);
freopen("scarlet.out", "w", stdout);
read(n, m);
for (int i = 0; i < n; i++) {
read(a[i]);
sum[i] = sum[max(0, i - 1)] + a[i];
}
sq = sqrt(n);
for (int i = 1; i <= sq; i++) {
st[i] = (i - 1) * sq + 1;
ed[i] = i * sq;
}
ed[sq] = n;
for (int i = 1; i <= sq; i++) {
for (int j = st[i]; j <= ed[i]; j++) {
belog[j] = i;
}
}
long long s, x, y, k;
for (int i = 1; i <= m; i++) {
read(s, x, y);
if (s == 1) {
read(k);
if (x <= sq) {
y = min(y, x - 1);
for (int j = 0; j <= y; j++) {
f[x][j] += (j + 1) * k;
}
for (int j = y + 1; j <= x - 1; j++) {
f[x][j] += (y + 1) * k;
}
} else {
y = min(y, x - 1);
for (int j = 0; j <= n - 1; j += x) {
c[j + 1] += k;
if (j + 1 + y + 1 <= n) c[j + 1 + y + 1] -= k;
ci[j + 1] += (j + 1) * k;
if (j + 1 + y + 1 <= n) ci[j + 1 + y + 1] -= (j + 1 + y + 1) * k;
sc[belog[j + 1]] += k;
sci[belog[j + 1]] += (j + 1) * k;
if (j + 1 + y + 1 <= n) sc[belog[j + 1 + y + 1]] -= k;
if (j + 1 + y + 1 <= n) sci[belog[j + 1 + y + 1]] -= (j + 1 + y + 1) * k;
}
}
} else {
long long ans = w(x - 1, y - 1);
long long sumc = 0, sumci = 0;
for (int j = 1; j <= belog[x] - 1; j++) {
sumc += sc[j];
sumci += sci[j];
}
for (int j = st[belog[x]]; j <= x - 1; j++) {
sumc += c[j];
sumci += ci[j];
}
ans -= (1ll * x * sumc - sumci);
for (int j = x; j <= min(y, 1ll * ed[belog[x]]); j++) {
sumc += c[j];
sumci += ci[j];
}
for (int j = belog[x] + 1; j <= belog[y] - 1; j++) {
sumc += sc[j];
sumci += sci[j];
}
if (belog[x] != belog[y]) {
for (int j = st[belog[y]]; j <= y; j++) {
sumc += c[j];
sumci += ci[j];
}
}
ans += (1ll * (y + 1) * sumc - sumci);
write(ans,'\n');
}
}
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· winform 绘制太阳,地球,月球 运作规律
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理