test20230906考试总结
前言#
这一场比赛已经彻底让我自闭了,看不起 whk 的我逐渐开始搞 whk 了,可见我有多自闭了。
赛时得分明细:
intervals | trans | ez | traffic | Total |
---|---|---|---|---|
40 | 60 | 0 | 0 | 100 |
改题明细:
intervals | trans | ez | traffic | Total |
---|---|---|---|---|
100 | 90 | 100 | 100 | 390 |
改题还算有进步的,只是效率慢了点qwq。
为了方便以后复习,所以每一道题都搬到了 luogu 上 ,由于版权问题,仅个人可见。
intervals#
Problem#
给定
Solve#
分类讨论:
- 若
时,一个区间都不能选,因为一旦选了哪怕一个区间就会做负贡献了。 - 若
时,所有区间都要选,由于所有的区间都包含零点,所以所有区间都有交。现在想要让交的区间长度更小,并的区间长度更大。选上所有区间一定不会更劣。 - 若
时,至少选一个区间,但当 时,负贡献更多,那还不如不选。 - 若
时,考虑所有可能的并都能用至多两个区间表示出来,并且交集不为空。所以暴力的做法是枚举两个区间然后统计答案。
这里有一个小 trick:对于第
算法一
这里需要推一下式子:令
令
枚举
算法二
可以注意到,答案是一边枚举一边计算贡献的。所以从前往后枚举,所以
Code#
算法一:权值线段树写法
#include<bits/stdc++.h>
#define int long long
#define rint register int
#define For(i,l,r) for(rint i=l;i<=r;++i)
#define FOR(i,r,l) for(rint i=r;i>=l;--i)
#define mod 998244353
#define inf 1e18
using namespace std;
inline int read() {
rint x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
return x*f;
}
const int N = 1e5 + 10;
struct Node {
int l, r;
} a[N], b[N];
struct Seg_tree {
int l, r, mx;
} t[N * 100];
int n, len, A, B, ans = -inf, idx, rt, lmin = inf, rmin = inf, lmax = -inf, rmax = -inf;
bool cmp(Node x, Node y) {
return (x.l == y.l ? x.r > y.r : x.l < y.l);
}
void pushup(int p) {
t[p].mx = max(t[t[p].l].mx, t[t[p].r].mx);
}
void up(int &p, int l, int r, int k, int val) {
if(!p) p = ++idx, t[p].mx = -inf;
if(l == r) {
t[p].mx = max(t[p].mx, val);
return ;
}
int mid = (l + r) >> 1;
if(k <= mid) up(t[p].l, l, mid, k, val);
else up(t[p].r, mid + 1, r, k, val);
pushup(p);
}
int ask(int p, int l, int r, int ql, int qr) {
if(ql <= l && r <= qr) {
return t[p].mx;
}
int mid = (l + r) >> 1, ans = -inf;
if(ql <= mid) ans = max(ans, ask(t[p].l, l, mid, ql, qr));
if(qr > mid) ans = max(ans, ask(t[p].r, mid + 1, r, ql, qr));
return ans;
}
signed main() {
n = read();
For(i,1,n) a[i] = (Node){read(), read()};
For(i,1,n) {
lmin = min(lmin, a[i].l);
lmax = max(lmax, a[i].l);
rmin = min(rmin, a[i].r);
rmax = max(rmax, a[i].r);
}
A = read(), B = read();
sort(a + 1, a + n + 1, cmp);
int maxn = -inf;
For(i,1,n) {
if(maxn < a[i].r) a[++len] = a[i];
maxn = max(maxn, a[i].r);
}
n = len;
ans = max(0ll, A * (rmin - lmax + 1) + B * (rmax - lmin + 1));
For(i,1,n) {
up(rt, -1e9, 1e9, a[i].l, (-a[i].l * A + B * a[i].r));
}
For(i,1,n) {
ans = max(ans, ask(rt, -1e9, 1e9, a[i].l, a[i].r) + a[i].r * A - B * a[i].l + A + B);
}
cout << ans << '\n';
return 0;
}
算法二:前缀 Max 写法
#include<bits/stdc++.h>
#define int long long
#define rint register int
#define For(i,l,r) for(rint i=l;i<=r;++i)
#define FOR(i,r,l) for(rint i=r;i>=l;--i)
#define mod 998244353
#define inf 1e18
using namespace std;
inline int read() {
rint x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
return x*f;
}
const int N = 1e5 + 10;
struct Node {
int l, r;
} a[N];
int n, len, A, B, ans = 0, lmin = inf, rmin = inf, lmax = -inf, rmax = -inf, maxn;
bool cmp(Node x, Node y) {
return (x.l == y.l ? x.r > y.r : x.l < y.l);
}
signed main() {
n = read();
For(i,1,n) a[i] = (Node){read(), read()};
A = read(), B = read();
For(i,1,n) {
lmin = min(lmin, a[i].l);
lmax = max(lmax, a[i].l);
rmin = min(rmin, a[i].r);
rmax = max(rmax, a[i].r);
maxn = max(maxn, a[i].r - a[i].l + 1);
}
if(A <= 0 && B <= 0) ans = 0;
else if(A <= 0 && B > 0) ans = A * (rmin - lmax + 1) + B * (rmax - lmin + 1);
else if(A > 0 && B <= 0) ans = max(ans, (A + B) * maxn);
else {
sort(a + 1, a + n + 1, cmp);
int maxi = -inf, maxx = -inf;
For(i,1,n) {
if(maxx < a[i].r) a[++len] = a[i];
maxx = max(maxx, a[i].r);
}
n = len;
For(i,1,n) {
maxi = max(maxi, A * a[i].r - B * a[i].l);
ans = max(ans, maxi + A * (-a[i].l) + B * a[i].r + A + B);
}
}
cout << ans << '\n';
return 0;
}
trans#
Problem#
给定一个长度为
Solve#
考虑 dp。
设
时间复杂度
还没完,由于在
这样可以多过一个点,拿到
Code#
以下时
#include<bits/stdc++.h>
#define int long long
#define rint register int
#define For(i,l,r) for(rint i=l;i<=r;++i)
#define FOR(i,r,l) for(rint i=r;i>=l;--i)
#define mod 998244353
using namespace std;
inline int read() {
rint x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
return x*f;
}
const int N = 3e6 + 10;
int n, a[N], sum[N], dp[N], dp2[N], lastj;
signed main() {
n = read();
For(i,1,n) a[i] = read(), sum[i] = sum[i-1] + a[i];
memset(dp, 0x3f, sizeof dp);
memset(dp2, 0x3f, sizeof dp2);
dp[0] = 0, dp2[0] = 0;
For(i,1,n) {
FOR(j,i-1,lastj) {
int x = sum[i] - sum[j];
if(x >= dp2[j]) {
dp[i] = dp[j] + i - j - 1;
dp2[i] = x;
lastj = j;
cout << j << '\n';
break;
}
}
For(j,lastj,i-1) cout << dp2[j] << ' ';
cout << '\n';
}
cout << dp[n] << '\n';
return 0;
}
ez#
Problem#
给出
显然, 一共有
Solve#
正解不太会,但是可以用暴力创!!
操作以每一行为基准,每一次从优先队列里取出前
这样最后优先队列里的数一定是前
时间复杂度
Code#
#include<bits/stdc++.h>
#define int long long
#define rint register int
#define For(i,l,r) for(rint i=l;i<=r;++i)
#define FOR(i,r,l) for(rint i=r;i>=l;--i)
#define mod 998244353
using namespace std;
inline int read() {
rint x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
return x*f;
}
const int N = 6e2 + 10, M = 3e6 + 10;
int n, a[N][N];
signed main() {
while(scanf("%d", &n) != EOF) {
priority_queue<int> q;
vector<int> p;
For(i,1,n) For(j,1,n) a[i][j] = read();
For(i,1,n) {
if(i == 1) {
For(j,1,n) q.push(a[i][j]);
continue;
}
p.clear();
while(!q.empty()) {
p.push_back(q.top()); q.pop();
}
For(j,1,n) {
FOR(k,n-1,0) {
int x = p[k] + a[i][j];
if(q.size() != n) q.push(x);
else if(q.top() > x) q.pop(), q.push(x);
else break;
}
}
}
p.clear();
while(!q.empty()) {
p.push_back(q.top()); q.pop();
}
FOR(i,n-1,0) cout << p[i] << ' ';
cout << '\n';
}
return 0;
}
traffic#
Problem#
给定一张由
Solve#
正难则反,考虑保留(不调查)哪些边可以推出所有边。
通过手模样例可得,边的状态(连边方向)与是否能推出边无关,只在乎一个点的入度和出度。
可以发现,假如保留的边形成了环,则其一定不合法。换句话说,保留的边不能有环。大胆猜测其形态为一棵树。
现在是要被调查的边,也就是被删除的边的代价尽可能小,那么,保留的边的代价要尽可能大。所以,大胆猜测其为最大生成树。
最后答案为总代价之和减去最大生成树的代价之和。
由于负代价边选了一定不会劣,所以要全选上,所以保留的边所组成的图为最大生成树森林。求最大生成树的时候要将负代价边去掉,图不一定连通。
Code#
#include<bits/stdc++.h>
#define int long long
#define rint register int
#define For(i,l,r) for(rint i=l;i<=r;++i)
#define FOR(i,r,l) for(rint i=r;i>=l;--i)
#define mod 998244353
using namespace std;
inline int read() {
rint x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
return x*f;
}
const int N = 5e5 + 10;
struct Node {
int u, v, w;
} e[N];
int n, m, f[N], ans, tot, W;
int find(int x) {
return (x == f[x] ? x : f[x] = find(f[x]));
}
bool cmp(Node x, Node y) {
return x.w > y.w;
}
void kurskal() {
sort(e + 1, e + m + 1, cmp);
For(i,1,m) {
int u = e[i].u, v = e[i].v;
if(find(u) == find(v)) continue;
f[find(u)] = find(v);
tot++;
ans += e[i].w;
if(tot == n-1) break;
}
}
signed main() {
n = read(), m = read();
For(i,1,n) f[i] = i;
For(i,1,m) {
int u = read(), v = read(), w = read();
W += w;
if(w > 0) e[i] = (Node){u, v, w};
}
kurskal();
cout << W - ans << '\n';
return 0;
}
作者:Daniel-yao
出处:https://www.cnblogs.com/Daniel-yao/p/17682686.html
版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】