2026-05-25~06-11 hetao1733837 的刷题记录

2026-05-25~06-11 hetao1733837 的刷题记录

05-25

祝 xxxalq ⁡ \operatorname{xxxalq} xxxalq 生日快乐🎂

LGP3075 USACO13FEB Partitioning the Farm G

原题链接:USACO13FEB Partitioning the Farm G

分析

最小化区域和最大值 让我想到了二分答案。难道是 DP?二分套 DP 似乎是不错的东西。

怎么写啊/ll

连个数据范围都没有吗?

难道是状压 DP?我觉得这个很合理啊,因为 N ≤ 15 N\le 15 N≤15。

原来是这样吗?我们一个维度 2 N − 1 2^{N-1} 2N−1 深搜,另一个维度二分答案!

正解

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;
const int N = 21;  // 稍微放大以匹配
int n, k, a[N][N], sum[N][N], c[N];
bool check(int row, int col, int x, int k){
    int cnt = 0;
    for (int i = 1; i <= row; i++){
        c[i] = 0;
    }
    for (int i = 1; i <= col; i++){
        for (int j = 1; j <= row; j++){
            c[j] += sum[j][i];
        }
        bool flag = false;
        for (int j = 1; j <= row; j++){
            flag |= (c[j] > x);
        }
        if (flag){
            cnt++;
            for (int j = 1; j <= row; j++){
                c[j] = sum[j][i];
                if (c[j] > x)
                    return false;
            }
        }
    }
    return cnt <= k;
}
int calc(int row, int col, int k){
    int l = 0, r = 225000;
    while (l < r){
        int mid = (l + r) >> 1;
        if (check(row, col, mid, k))
            r = mid;
        else
            l = mid + 1;
    }
    return l;
}
int main(){
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    cin >> n >> k;
    for (int i = 1; i <= n; i++){
        for (int j = 1; j <= n; j++){
            cin >> a[i][j];
        }
    }
    int ans = 0x3f3f3f3f;
    for (int num = 0; num < (1 << (n - 1)); num++){
        int cnt = 1;
        for (int i = 1; i <= n; i++){
            for (int j = 1; j <= n; j++){
                sum[cnt][j] += a[i][j];
            }
            cnt += (num >> (i - 1)) & 1;
        }
        if (k - (cnt - 1) >= 0){
            ans = min(ans, calc(cnt, n, k - (cnt - 1)));
        }
        for (int i = 1; i <= cnt; i++){
            for (int j = 1; j <= n; j++){
                sum[i][j] = 0;
            }
        }
    }
    cout << ans << '\n';
    return 0;
}

05-26

LGP3879 TJOI2010 阅读理解

原题链接:TJOI2010 阅读理解

分析

没啥的,STL🐂🍺!

正解

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;
int n, l, m;
map<string, set<int>> buc;
string s;
signed main(){
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	cin >> n;
	for (int i = 1; i <= n; i++){
		cin >> l;
		for (int j = 1; j <= l; j++){
			cin >> s;
			buc[s].insert(i);
		}
	}
	cin >> m;
	for (int i = 1; i <= m; i++){
		cin >> s;
		for (auto v : buc[s]){
			cout << v << " ";
		}
		cout << '\n';
	}
}

06-08

CF1876C Autosynthesis

原题链接:CF1876C Autosynthesis

分析

问号 \] \[ 问号 \] \[ 问号 \] {\[问号\]\[问号\]\[问号\]} \[问号\]\[问号\]\[问号

这是啥?我好饿,今天中午的饭真的是人类可以食用的吗?

也是采访到了学长的学习经验,缓和了和 xy 的关系好吧。但是感觉 xy 在点我啊。

哦,难道说把一个元素和那个与这个元素下标一样的连在一起?

那么,如果不连通,显然就 G 了。

那要是连通怎么办?要是隔一个选一个显然不是很好实现吧?

不连通真的会 G 吗?

从某些方面似乎不会......好久没有刷题了/ll


哦,原来是 fqh 的题吗/jy

咋是 内向基环树

即,我们把所有的 i i i 指向 a i a_i ai,那么,形成内向基环树。若未圈出了 i i i,则选择他的出边,反之,不选择。

那么,对于所有未选择出边的点,他的入边最少有一条被选择;所有选择了出边的点,他所有的入边都没被选择。

所有叶子节点都要选择出边,剩下的直接做就行。

正解

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;
const int N = 1e6 + 10;
int n, a[N], b[N], in[N], id[N];
bool vis[N];
vector<int> buc;
queue<int> q;
int main(){
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    cin >> n;
    for (int i = 1; i <= n; i++){
        id[i] = i;
    }
    for (int i = 1; i <= n; i++){
        cin >> a[i];
        in[a[i]]++;
    }
    for (int i = 1; i <= n; i++){
        if (!in[i]){
            q.push(i);
            vis[i] = true;
        }
    }
    while (!q.empty()){
        int u = q.front();
        int v = a[u];
        q.pop();
        if (vis[v]){
            continue;
        }
        buc.push_back(a[u]);
        vis[v] = true;
        in[a[v]]--;
        if (!in[a[v]]){
            vis[a[v]] = true;
            q.push(a[v]);
        }
    }
    for (int i = 1; i <= n; i++){
        if (!vis[i]){
            for (int u = i; a[u] != u && !vis[a[u]]; u = a[a[u]]){
                buc.push_back(a[u]);
                vis[u] = vis[a[u]] = true;
            }
        }
    }
    for (int i = 1; i <= n; i++){
        if (!vis[i]){
            cout << -1;
            return 0;
        }
    }
    int sum = 0;
    for (auto v : buc){
        b[v] = 1;
    }
    for (int i = 1; i <= n; i++){
        sum += b[i];
    }
    cout << n - sum << '\n';
    for (int i = 1; i <= n; i++){
        if (!b[i]){
            cout << a[i] << " ";
        }
    }
}

06-11

别给东外来的传球!!!

LGP11183 ROIR 2018 大数据处理 (Day2)

原题链接:ROIR 2018 大数据处理 (Day2)

分析

有一种区间覆盖的感觉。咦,下节咋还有物理课/ll


物理课想了 10min ,觉得应该搞清楚最暴力的怎么搞。就是,怎么证明这个东西始终有解。写到这句话的时候,我已经明白了,就是说,每个数都是 1 的倍数,所以说,最暴力的情况显然是一个一个做。

那么,这个题似乎明朗了一点,但也只是一点。我想吃饭/ll

仔细思考一下。

画了一下......也就是说,我们可以对于所有偶数进行质因数分解,那么,有几个 2 ,就可以向后延伸多少......

然后呢?一个部分的拆解......这个是好做的吧......(虽然我不会)但是这是一个非常顺滑的 DP

好吧,我决定看题解。但是,我没有看出来这里面要用什么数据结构。


这题的巧思在于,这个 2 i 2^i 2i 可以让人联想到 线段树!!!所有合法区间都对应了线段树上的点。

设 d p p o s , c dp_{pos,c} dppos,c 表示把线段树 p o s pos pos 点全部染成要求的最小的操作次数。这个题解写成这样会不会被wk爆掉?

转移有:

d p p o s , c = min ⁡ { d p l s , c + d p r s , c − 1 d p l s , c + m n r s d p l r s , c + m n l s dp_{pos,c}=\min\begin{cases} dp_{ls,c}+dp_{rs,c}-1\\ dp_{ls,c}+mn_{rs}\\ dp_{lrs,c}+mn_{ls} \end{cases} dppos,c=min⎩ ⎨ ⎧dpls,c+dprs,c−1dpls,c+mnrsdplrs,c+mnls

其中, m n p o s = min ⁡ d p p o s , c mn_{pos}=\min dp_{pos,c} mnpos=mindppos,c。

其实每次算就行了,可以优化一维,所以,最终的复杂度来到了 O ( n k ) O(nk) O(nk)。

正解

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;
const int N = 100005;
const int MAXN = 3000010;
int k, n, m;
int tot, rt, cnt;
vector<int> dp[MAXN], col[MAXN];
int mn[MAXN];
map<int, int> buc;
struct segtree{
    int ls, rs, val;
}tr[MAXN];
int tmp[N];
void modify(int &p, int l, int r, int s, int t, int v){
    if (!p) 
        p = ++tot;
    if (s <= l && r <= t){
        tr[p].val = v;
        return ;
    }
    int mid = (l + r) >> 1;
    if (s <= mid) 
        modify(tr[p].ls, l, mid, s, t, v);
    if (t > mid)  
        modify(tr[p].rs, mid + 1, r, s, t, v);
}
void calc(int p){
    int cur = ++tot;
    int l, r;
    dp[cur].clear();
    col[cur].clear();
    if (tr[p].val){
        dp[cur].push_back(1);
        col[cur].push_back(tr[p].val);
        mn[cur] = 1;
        return ;
    }
    mn[cur] = 0x3f3f3f3f;
    calc(tr[p].ls);
    l = tot;
    calc(tr[p].rs);
    r = tot;
    for (int i = 0; i < (int)dp[l].size(); i++){
        dp[cur].push_back(dp[l][i] + mn[r]);
        col[cur].push_back(col[l][i]);
        tmp[col[l][i]] = i + 1;
        mn[cur] = min(mn[cur], dp[l][i] + mn[r]);
    }
    for (int i = 0; i < (int)dp[r].size(); i++){
        int pos = tmp[col[r][i]] - 1;
        if (pos != -1){
            dp[cur][pos] = min(dp[cur][pos], dp[r][i] + min(dp[l][pos] - 1, mn[l]));
            mn[cur] = min(mn[cur], dp[cur][pos]);
        } 
        else{
            dp[cur].push_back(dp[r][i] + mn[l]);
            col[cur].push_back(col[r][i]);
            mn[cur] = min(mn[cur], dp[r][i] + mn[l]);
        }
    }
    for (int i = 0; i < (int)dp[l].size(); i++)
        tmp[col[l][i]] = 0;
    tot = cur; 
}
signed main(){
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    cin >> k >> n >> m;
    int l = 0, r = -1;
    for (int i = 1; i <= n; i++){
        int c, v;
        cin >> c >> v;
        r = l + c - 1;
        if (!buc[v]) 
            buc[v] = ++cnt;
        modify(rt, 0, (1 << k) - 1, l, r, buc[v]);
        l = r + 1;
    }
    tot = 0;
    calc(rt);
    cout << mn[1];
    return 0;
}
相关推荐
cheems95271 小时前
[算法手记] 滑动窗口最大值
算法
洛水水1 小时前
【力扣100题】82.有效的括号
c++·算法·leetcode
XGeFei1 小时前
时序算法 —— LSTM、ARIMA、随机森林
算法·随机森林·lstm
湖南天硕国产SSD2 小时前
工业存储可靠性进阶:天硕工业固态硬盘动态温控与寿命优化技术实践
网络·数据库·算法·工业存储·天硕存储·工业固态硬盘
legend050709ComeON2 小时前
常见面试题-leetcode
数据结构·算法·leetcode
初中就开始混世的大魔王2 小时前
7 Fast DDS-持久化服务
c++·人工智能·中间件·自动驾驶·信息与通信
Smilecoc2 小时前
决策树(一):决策树基本原理
算法·决策树·机器学习
weixin_307779132 小时前
从工具到协作者:AI在后端研发中的流程重构与组织赋能
人工智能·后端·python·算法·自动化
爱吃生蚝的于勒2 小时前
QT开发第三章——常用控件
linux·服务器·开发语言·前端·javascript·c++·qt