9.21模拟赛解题报告

题目及数据:

https://www.lanzous.com/i1xdr8h

心路历程

预计分数:$100+ 100 +60 = 260$

实际得分:$100 + 100 + 0 = 200$

我这次检查了三遍绝对没算错!!!

上来看T1,咦?我好像做过这题在仙人掌上的版本。。树上更简单吧。。写+拍 1h,期间拍出了暴力的两个bug。。。

看T2,好难啊,不会做啊 qwq。。然后开始强行套算法。恩。把单调队列套进去发现是可行的。。而且好像还可以无视题目的一些性质。。嘿嘿嘿这题有加强版了

T3更神仙。。想了一个并查集优化暴力的$n^2$算法,然后写挂了。。。自己造的输出跑的贼快,一上评测机就死循环。。

因为昨天晚上打cf特别困,而且自我感觉$260$应该不低了,就睡了一个半小时。。。。。。。。。

T1

听大佬们说是原题啊Orz

我居然不知道 我好像是做过然后忘的一干二净。。

很显然,把路径拆开,判断lca之间的关系即可

#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<vector>
#include<cstring>
#define getchar() ((p1 == p2) && (p2 = (p1 = buf) + fread(buf, 1, 1 << 21, stdin), p1 == p2) ? EOF : *p1++)
using namespace std;
const int MAXN = 1e5 + 10;
char buf[(1 << 21)], *p1 = buf, *p2 = buf;
inline int read() {
    char c = getchar(); int x = 0, f = 1;
    while(c < '0' || c > '9') {if(c == '-') f = -1; c = getchar();}
    while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
    return x * f;
}
int T, N, Q, fa[MAXN], dep[MAXN], top[MAXN], son[MAXN], siz[MAXN];
vector<int> v[MAXN];
void init() {
    for(int i = 1; i <= N; i++) v[i].clear();
    memset(top, 0, sizeof(top));
    memset(son, 0, sizeof(son));
}
void dfs1(int x, int _fa) {
    siz[x] = 1; fa[x] = _fa;
    for(int i = 0; i < v[x].size(); i++) {
        int to = v[x][i];
        if(to == _fa) continue;
        dep[to] = dep[x] + 1;
        dfs1(to, x);
        siz[x] += siz[to];
        if(siz[to] > siz[son[x]]) son[x] = to;
    }
}
void dfs2(int x, int topf) {
    top[x] = topf;
    if(!son[x]) return ;
    dfs2(son[x], topf);
    for(int i = 0; i < v[x].size(); i++) {
        int to = v[x][i];
        if(top[to]) continue;
        dfs2(to, to);
    }
}
int LCA(int x, int y) {
    while(top[x] != top[y]) {
        if(dep[top[x]] < dep[top[y]]) swap(x, y);
        x = fa[top[x]];
    }
    if(dep[x] > dep[y]) swap(x, y);
    return x;
}
bool check(int a, int x, int y) {
    if(dep[x] < dep[y]) swap(x, y);
    if(LCA(a, x) == a && LCA(a, y) == y) return 1;
    else return 0;
}
int main() {
    freopen("railway.in", "r", stdin);
    freopen("railway.out", "w", stdout);
    T = read(); 
    while(T--) {
        N = read(); Q = read();
        init();
        for(int i = 1; i <= N - 1; i++) {
            int x = read(), y = read();
            v[x].push_back(y); v[y].push_back(x);
        }
        dep[1] = 1; dfs1(1, 0);
        dfs2(1, 1);
        while(Q--) {
            int xx1 = read(), yy1 = read(), xx2 = read(), yy2 = read();
            int lca1 = LCA(xx1, yy1), lca2 = LCA(xx2, yy2);
            if(check(lca1, xx2, lca2) || check(lca1, yy2, lca2) || check(lca2, xx1, lca1) || check(lca2, yy1, lca1)) puts("YES");
            else puts("NO");
        }
    }
    return 0;
}
T1

T2

式子化简完了之后应该是求

$$\sum_{i = 1}^n \sum_{j = 1}^i mx - mn$$

其中

$mx = max(a[j], a[j+1], \dots a[i])$

$mn = min(a[j], a[j+1], \dots a[i])$

单调栈维护即可。。。。

#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<iostream>
#define LL long long 
using namespace std;
const LL MAXN = 1e5 + 10;
inline LL read() {
    char c = getchar(); LL x = 0, f = 1;
    while(c < '0' || c > '9') {if(c == '-') f = -1; c = getchar();}
    while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
    return x * f;
}
LL T, N;
LL a[MAXN], q[MAXN];
LL solve() {
    LL h = 1, t = 0, ans = 0, sum = 0;
    for(LL i = 1; i <= N; i++) {
        while(h <= t && a[i] > a[q[t]]) sum -= a[q[t]] * (q[t] - q[t - 1]), t--;
        q[++t] = i;
        ans += a[i] * (q[t] - q[t - 1]) + sum;
        sum += a[i] * (q[t] - q[t - 1]);
    }
    return ans;
}
int main() {
    freopen("count.in", "r", stdin);
    freopen("count.out", "w", stdout);
    T = read();
    while(T--) {
        N = read();
        for(LL i = 1; i <= N; i++) a[i] = read();
        LL ans = solve();
        for(LL i = 1; i <= N; i++) a[i] = -a[i];
        LL ans2 = solve();
        cout << ans + ans2 << endl;
    }
    return 0;
}
T2

T3

不明白出这种题有什么意义。。。

dsu on tree, set,这都是noip知识点????

而且标算好像就是在想尽各种方法优化暴力。。。

考虑直接算一条边的贡献

首先考虑暴力怎么算

对于一条边来说,如果子树内有连续的区间,比如$[1, 2, 3, 4]$那么在统计他们的答案时显然不会经过该边,他们对答案的贡献为$\frac{n(n -1)}{2} $

用总贡献减去即可。

然后可以分成子树内和子树外讨论,子树内用并查集维护,子树外用set维护并查集的补集

做完了。。。

代码里面的solve函数是抄的标算,,,实在写不出来啊qwq

#include<bits/stdc++.h>
#define LL long long 
using namespace std;
const int MAXN = 1e5 + 10;
inline int read() {
    char c = getchar(); int x = 0, f = 1;
    while(c < '0' || c > '9') {if(c == '-') f = -1; c = getchar();}
    while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
    return x * f;
}
int N, dep[MAXN], siz[MAXN], son[MAXN], dsu[MAXN], Son, vis[MAXN], ds[MAXN];
vector<int> v[MAXN];
set<int> s;
LL AnsOut, AnsIn, ans;
void dfs(int x, int _fa) {
    siz[x] = 1;
    for(int i = 0; i < v[x].size(); i++) {
        int to = v[x][i]; if(to == _fa) continue;
        dfs(to, x);
        siz[x] += siz[to];
        if(siz[to] > siz[son[x]]) son[x] = to;
    }
}
LL calc(LL x) {
    return x * (x - 1) / 2;
}
void Clear() {
    s.clear(); AnsOut = calc(N); AnsIn = 0;
    s.insert(0); s.insert(N + 1);
}
int find(int x) {
    return dsu[x] == x ? dsu[x] : dsu[x] = find(dsu[x]);
}
void solve(int x) {
    s.insert(x);
    set<int>::iterator s1, s2, it;
    s1 = s2 = it = s.find(x);
    s1--; s2++;
    AnsOut -= calc((*s2) - (*s1) - 1);
    AnsOut += calc((*s2) - (*it) - 1) + calc((*it) - (*s1) - 1);
    vis[x] = 1;
    if(vis[x - 1]) {
        int fx = find(x - 1), fy = find(x);
        AnsIn += ds[fx] * ds[fy];
        dsu[fx] = fy;
        ds[fy] += ds[fx];
    }
    if(vis[x + 1]) {
        int fx = find(x + 1), fy = find(x);
        AnsIn += ds[fx] * ds[fy];
        dsu[fx] = fy;
        ds[fy] += ds[fx];
    }
}
void Add(int x, int fa) {
    solve(x);
    for(int i = 0; i < v[x].size(); i++) {
        int to = v[x][i];
        if(to == fa || to == Son) continue;
        Add(to, x);
    }
}
void Delet(int x, int fa) {
    vis[x] = 0; ds[x] = 1; dsu[x] = x;
    for(int i = 0; i < v[x].size(); i++) {
        int to = v[x][i];
        if(to == fa) continue;
        Delet(to, x);
    }
} 
void dfs2(int x, int fa, int opt) {
    for(int i = 0; i < v[x].size(); i++) {
        int to = v[x][i];
        if(to == fa || (to == son[x])) continue;
        dfs2(to, x, 0);
    }
    if(son[x]) dfs2(son[x], x, 1); Son = son[x];
    Add(x, fa);
    ans += calc(N) - AnsIn - AnsOut;
    if(opt == 0) Delet(x, fa), Clear(), Son = 0;
}
main() {
    N = read();
    for(int i = 1; i <= N - 1; i++) {
        int x = read(), y = read();
        v[x].push_back(y); v[y].push_back(x);
    }
    for(int i = 1; i <= N; i++) dsu[i] = i, ds[i] = 1;
    dep[1] = 1; dfs(1, 0);
    Clear(); 
    dfs2(1, 0, 0);
    cout << ans;
    return 0;
}
/*
10
1 9
9 7
9 5
5 3
9 4
4 8
1 10
1 2
3 6

4
1 4
1 3
2 4
*/
T3

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
目标检测(Object Detection)是计算机视觉领域的一个核心问题,其主要任务是找出图像中所有感兴趣的目标(物体),并确定它们的类别和位置。以下是对目标检测的详细阐述: 一、基本概念 目标检测的任务是解决“在哪里?是什么?”的问题,即定位出图像中目标的位置并识别出目标的类别。由于各类物体具有不同的外观、形状和姿态,加上成像时光照、遮挡等因素的干扰,目标检测一直是计算机视觉领域最具挑战性的任务之一。 二、核心问题 目标检测涉及以下几个核心问题: 分类问题:判断图像中的目标属于哪个类别。 定位问题:确定目标在图像中的具体位置。 大小问题:目标可能具有不同的大小。 形状问题:目标可能具有不同的形状。 三、算法分类 基于深度学习的目标检测算法主要分为两大类: Two-stage算法:先进行区域生成(Region Proposal),生成有可能包含待检物体的预选框(Region Proposal),再通过卷积神经网络进行样本分类。常见的Two-stage算法包括R-CNN、Fast R-CNN、Faster R-CNN等。 One-stage算法:不用生成区域提议,直接在网络中提取特征来预测物体分类和位置。常见的One-stage算法包括YOLO系列(YOLOv1、YOLOv2、YOLOv3、YOLOv4、YOLOv5等)、SSD和RetinaNet等。 四、算法原理 以YOLO系列为例,YOLO将目标检测视为回归问题,将输入图像一次性划分为多个区域,直接在输出层预测边界框和类别概率。YOLO采用卷积网络来提取特征,使用全连接层来得到预测值。其网络结构通常包含多个卷积层和全连接层,通过卷积层提取图像特征,通过全连接层输出预测结果。 五、应用领域 目标检测技术已经广泛应用于各个领域,为人们的生活带来了极大的便利。以下是一些主要的应用领域: 安全监控:在商场、银行
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值