20260713总结

总结

  1. 多多调试,因为你想到的方法很可能是正解。
  2. 锻炼调题能力,不然在一道题上耗时太久。
  3. 多看题,先打好一定能拿到的部分分再去写其他题的正解。
  4. 不要认为你的分数已经够了就开始摆烂,因为你会做的别人也会。

T1 排列鞋子

T2 P3459 [POI 2007] MEG-Megalopolis

场切了,没有思维,全是码量。

考场上坚持调试这一题,虽然最后过了但是调试这一题的时间太久了,导致放弃了T4。

思路

首先注意到题目中给出的是一棵树。初始每一条边权为 \(1\) ,那么修改边相当于将边权置为 \(0\)

考虑把这棵树拍到 dfn 序上,并记录每个节点的深度。

由于每一棵子树在 dfn 序列中都是连续的。所以修改和查询操作相当于区间修改和单点查询。

考虑用线段树维护深度。

代码

点击查看代码
#include <bits/stdc++.h>
using namespace std;
const int N = 250005;
int cnt, n, m, dep[N], dfn[N], dfn2[N];
struct node
{
    int l, r;
} a[N];
struct tree
{
    int data, lzy;
} w[N << 2];
vector<int> g[N];
bool InRange(int l, int r, int L, int R) { return (l >= L) && (r <= R); }
bool OutofRange(int l, int r, int L, int R) { return (r < L) || (l > R); }
void pushup(int u)
{
    w[u].data = w[u * 2].data + w[u * 2 + 1].data;
}
void pushdown(int u, int l, int r)
{
    if (w[u].lzy == 0)
        return;
    w[u * 2].lzy += w[u].lzy, w[u * 2 + 1].lzy += w[u].lzy;
    int mid = l + r >> 1;
    w[u * 2].data -= (mid - l + 1) * w[u].lzy;
    w[u * 2 + 1].data -= (r - mid) * w[u].lzy;
    w[u].lzy = 0;
}
void build(int u, int l, int r)
{
    if (l == r)
    {
        w[u].data = dep[l];
        return;
    }
    int mid = l + r >> 1;
    build(u * 2, l, mid);
    build(u * 2 + 1, mid + 1, r);
    pushup(u);
}
void update(int u, int l, int r, int L, int R)
{
    if (InRange(l, r, L, R))
    {
        w[u].lzy++;
        w[u].data -= r - l + 1;
        return;
    }
    if (OutofRange(l, r, L, R))
        return;
    int mid = l + r >> 1;
    pushdown(u, l, r);
    update(u * 2, l, mid, L, R);
    update(u * 2 + 1, mid + 1, r, L, R);
    pushup(u);
}
int query(int u, int l, int r, int L, int R)
{
    if (InRange(l, r, L, R))
        return w[u].data;
    if (OutofRange(l, r, L, R))
        return 0;
    int mid = l + r >> 1;
    pushdown(u, l, r);
    return query(u * 2, l, mid, L, R) + query(u * 2 + 1, mid + 1, r, L, R);
}
int dfs(int x, int fa, int sum)
{
    a[x] = {++cnt, cnt};
    dfn[x] = cnt;
    dfn2[cnt] = x;
    dep[cnt] = sum;
    for (int v : g[x])
    {
        if (v == fa)
            continue;
        a[x].r = dfs(v, x, sum + 1);
    }
    return a[x].r;
}
signed main()
{
    // freopen("meg.in", "r", stdin);
    // freopen("meg.out", "w", stdout);
    cin >> n;
    for (int i = 1; i < n; i++)
    {
        int a, b;
        cin >> a >> b;
        g[a].push_back(b);
        g[b].push_back(a);
        // cin >> dep[i];
    }
    dfs(1, 0, 0);
    build(1, 1, n);
    // for (int i = 1; i <= n; i++)
    // {
    //     cout << a[i].l << " " << a[i].r << endl;
    // }
    // for (int i = 1; i <= n; i++)
    // {
    //     cout << dfn[i] << " ";
    // }
    // cout << endl;
    // for (int i = 1; i <= n; i++)
    // {
    //     cout << query(1, 1, n, dfn[a[i].l], dfn[a[i].l]) << " ";
    // }
    cin >> m;
    for (int i = 1; i <= n + m - 1; i++)
    {
        char op;
        cin >> op;
        if (op == 'W')
        {
            int x;
            cin >> x;
            cout << query(1, 1, n, dfn[x], dfn[x]) << endl;
            // cout << dep[dfn[x]] << endl;
        }
        if (op == 'A')
        {
            int x, y;
            cin >> x >> y;
            update(1, 1, n, a[y].l, a[y].r);
            // for (int i = 1; i <= n; i++)
            // {
            //     cout << query(1, 1, n, a[i].l, a[i].l) << " ";
            // }
            // cout << endl;
        }
    }
}

T3 P3558 [POI 2013] BAJ-Bytecomputer

这道题之前考过,但是由于我之前的懒惰,一直都没有做这道题。

很好的一道分类讨论题。

思路

动态规划

猜测结论:按照优策略操作完后序列中只有 \(0\)\(1\)\(-1\)

\(dp[i][j]\) 为第 \(i\) 位变为 \(j - 1\) (防止数组下标为负),且序列合法时最小的操作次数。

初始化:\(dp[1][a[1] + 1]\)\(0\),其他全为 \(inf\)

然后就从 \(dp[2]\) 开始转移,分讨:

  • \(a[i] = -1\)

因为 \(a[i]\) 已经是 \(-1\) 了,所以 \(dp[i][0] = dp[i - 1][0]\)

\(a[i - 1]\) 初始为 \(1\) 时,\(a[i]\) 才有可能变为 \(0\),所以 \(dp[i][1] = min(dp[i - 1][0], dp[i - 1][1]) + 1\)。否则为 \(inf\)

同理,\(dp[i][2] = min(dp[i - 1][0], min(dp[i - 1][1], dp[i - 1][2])) + 2\)。但由于前一个数可以变成一了,所以当 \(a[i - 1] != 1\) 时,\(dp[i][2] = dp[i - 1][2] + 2\)

  • \(a[i] = 0\)\(a[i] = 1\) 时同理。

代码

点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N = 1e6 + 5;
const int inf = 1e9;
int dp[N][3], a[N], n, ans = inf;
signed main()
{
	scanf("%lld", &n);
	for(int i = 1; i <= n; i ++) scanf("%lld", &a[i]);
	if(a[1] == -1) dp[1][1] = inf, dp[1][2] = inf;
	if(a[1] == 0) dp[1][0] = inf, dp[1][2] = inf;
	if(a[1] == 1) dp[1][0] = inf, dp[1][1] = inf;
	for(int i = 2; i <= n; i ++)
	{
		if(a[i] == -1)
		{
			dp[i][0] = dp[i - 1][0];
			if(a[i - 1] == 1) dp[i][1] = min(dp[i - 1][0], dp[i - 1][1]) + 1;
			else dp[i][1] = inf;
			if(a[i - 1] == 1) dp[i][2] = min(dp[i - 1][0], min(dp[i - 1][1], dp[i - 1][2])) + 2;
			else dp[i][2] = dp[i - 1][2] + 2;
		}
		if(a[i] == 0)
		{
			dp[i][0] = dp[i - 1][0] + 1;
			dp[i][1] = min(dp[i - 1][0], dp[i - 1][1]);
			if (a[i - 1] == 1) dp[i][2] = min(dp[i - 1][0], min(dp[i - 1][1], dp[i - 1][2])) + 1;
			else dp[i][2] = dp[i - 1][2] + 1; 
		}
		if(a[i] == 1)
		{
			dp[i][0] = dp[i - 1][0] + 2;
			if(a[i - 1] == -1) dp[i][1] = min(dp[i - 1][0], dp[i - 1][1]) + 1;
			else dp[i][1] = dp[i - 1][0] + 1;
			dp[i][2] = min(dp[i - 1][0], min(dp[i - 1][1], dp[i - 1][2]));
		}
	}
	for(int i = 0; i <= 2; i ++)
	{
		ans = min(ans, dp[n][i]);
	}
	// printf("%lld %lld %lld\n", dp[n][0], dp[n][1], dp[n][2]);
	if(ans >= inf) cout << "BRAK" << endl;
	else cout << ans << endl;
}

贪心

还有个贪心解法的,但是我还没有学懂。

别人的题解

T4 P9525 [JOIST 2022] 团队竞技 / Team Contest

这一道题我做过的,考场上也想出了正解的东西。但是写完代码发现答案不对之后就没有调试了(当时代码实现方式不对导致特别复杂难调)

思路

这题不是一眼反悔贪心吗。

考虑各选出三只某个能力值最大的海狸(尽管会有重复)。然后记录每一只海狸的编号,如果编号有重复,那么就换成一只能力值次大的。

一直重复上述步骤,直到选出的三只海狸合法。

如果直到最后都没有选出来,则没有合法方案。

发现可以用三个优先队列维护海狸的每种能力值。

代码

点击查看代码
#include <bits/stdc++.h>
using namespace std;
const int N = 2e5 + 5;
int n, a[N], b[N], c[N], vis[N];
priority_queue<pair<int, int> > A, B, C;
signed main()
{
    cin >> n;
    for (int i = 1; i <= n; i++)
    {
        cin >> a[i] >> b[i] >> c[i];
        A.push(make_pair(a[i], i));
        B.push(make_pair(b[i], i));
        C.push(make_pair(c[i], i));
    }
    for (int i = 1; i <= n; i++)
    {
        int x = A.top().second, y = B.top().second, z = C.top().second;
        if (b[x] == b[y] || c[x] == c[z])
        {
            vis[x] = 1;
        }
            
        if (c[y] == c[z] || a[y] == a[x])
        {
            vis[y] = 1;
        }
            
        if (a[z] == a[x] || b[z] == b[y])
        {
            vis[z] = 1;
        }
            
        if (!vis[x] && !vis[y] && !vis[z])
        {
            cout << a[x] + b[y] + c[z];
            return 0;
        }
        while (!A.empty() && vis[A.top().second])
        {
            A.pop();
        }
            
        while (!B.empty() && vis[B.top().second])
        {
            B.pop();
        }
            
        while (!C.empty() && vis[C.top().second])
        {
            C.pop();
        }
            
    }
    cout << -1;
}
posted @ 2026-07-13 13:53  Luowj  阅读(88)  评论(0)    收藏  举报