三十年河东,三十年河西|

自动机

园龄:1年10个月粉丝:2关注:4

Codeforces Round 847 (Div. 3)

vp补题

赛时脑子不好使了,两题直接下班

C

题意:

已知一个n的排列,我们在黑板上每次都按顺序跳过一个数,将这个排列写下来。比如[1, 2, 3, 4]写下来就是
[2, 3, 4]
[1, 3, 4]
[1, 2, 4]
[1, 2, 4],现在给你黑板上写的n个序列, 求最开始的排列(行和行之间乱序)?

思路:

通过观察不难发现,第一个出现次数最多那个数肯定是排列里的第一个数p1,然后只要在剩下的序列里找到一个不包含p1的序列就可以了,

void solve() 
{
    int n; cin >> n;
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= n - 1; j++)
        {
            cin >> a[i][j];
        }
 
    int b = 0, maxx = 0;
    for (int i = 1; i <= n; i++)
    {
        cnt[a[i][1]]++;
    }
 
    for (int i = 1; i <= n; i++)
        if (cnt[i] > maxx)
        {
            b = i;
            maxx = cnt[i];
        }
 
 
    for (int i = 1; i <= n; i++)
    {
        int t = false;
        for (int j = 1; j <= n - 1; j++)
        {
            if (a[i][j] == b) t = true;
        }
 
        if (!t)
        {
            cout << b << ' ';
            for (int j = 1; j <= n - 1; j++)
                cout << a[i][j] << ' ';
            cout << endl;
        }
    }
    memset(cnt, 0, sizeof(cnt));
}

D

题意:

给你一个数组,你可以选一些数组成一个连续上升的序列(s, s + 1, s + 2....)。问你最少可以选多少组

思路:

可以先统计每个数出现的次数,然后从前往后扫一遍如果当前这个数符合条件,就加上它和前面一个数的差

void solve() 
{
    int n; cin >> n;
    map<int, int> mp;
    for (int i = 0; i < n; i++)
    {
        int x; cin >> x;
        mp[x]++;
    }  

    int last = -1, ans = 0;
    for (auto [x, y] : mp)
    {
        if (x > last + 1) ans += y; // 不符合条件,重新算
        else ans += max(0, y - mp[last]); // 如果小于零说明前面一个出现次数比它多的数已经把它用了,画个柱状图理解一下
        last = x;
    }
    cout << ans << endl;
}

E

题意:

给你一个整数x, 求两个整数ab,要求a, b满足x = a+b2 = a b

思路:

首先要知道一个性质:对于整数a, b如果a + b = A, a b = B, 那么两个数最小为AB2
结合上面的性质,不妨假设a = AB2, 又因为 x = B, A = 2 * B 所以 a = x2, b = A - a = 2 * x - a

#include <bits/stdc++.h>

using namespace std;
#define more ios_base::sync_with_stdio(0),cin.tie(0),cout.tie(0);
const int N = 2e5 + 5, MOD = 1e9 + 7, inf = 0x3f3f3f3f;
const long long INF = 1e18;
typedef long long LL;
typedef unsigned long long usLL;
typedef pair<int, int> PII;

void solve() 
{
    int x; cin >> x;
    int a = x / 2;
    int b = 2 * x - a;

    if ((a ^ b) == x) // 判断一下是不是符合条件
    {
        cout << a << ' ' << b << endl;
    }
    else
        cout << -1 << endl;
}

int main()
{
    more;
    int T;
    cin >> T;
    while (T--)
    {
        solve();
    }
    //solve();
    return 0;
}

F

题意:

给你一个棵树,让你按照顺序把树上每个节点染成黑色,要求输出每次染色之后黑色节点中距离最近的两个节点的距离(树的价值)

思路:

没啥思路,纯看jiangly代码和题解,可以感性的理解一下
假设当前要染色的节点为x, 上一次染色的节点位y和上一次染色后树的价值ans,那么当前染色完之后的答案应该是min(ans, dis[x])。dis[x]记录的y节点到y节点的距离, 证明的话可以把整棵树拉直成一条直线然后然后按照前面的方法依次加点,dis可以用bfs以每次加入的黑点为中心遍历求出(类似维护最短路),关键是更新后的值也必须小于ans(这样可以把复杂度优化到O(nn)), 不是很懂,可能是因为这样的数根本不会出现在后面的答案当中所以直接不搜了吧

void solve() 
{
	int n; cin >> n;
	std::vector<int> g(n + 1);
	for (int i = 1; i <= n; i++)
	{
		cin >> g[i];
	}

	vector<vector<int>> adj(n + 1);
	for (int i = 2; i <= n; i++)
	{
		int a, b; cin >> a >> b;
		adj[a].push_back(b);
		adj[b].push_back(a);
	}

	vector<int> dis(n + 1, inf);

	int ans = inf;
	for (int i = 1; i <= n; i++)
	{
		ans = min(ans, dis[g[i]]);
		if (i > 1) cout << ans << " \n"[i == n]; 

		queue<int> q;
		q.push(g[i]);
		dis[g[i]] = 0;

		while (!q.empty())
		{
			int x = q.front();
			q.pop();

			for (auto y : adj[x])
			{
				if (dis[x] + 1 < dis[y] && dis[x] + 1 < ans)
				{
					dis[y] = dis[x] + 1;
					q.push(y);
 				}
			}
		}
	}
}

本文作者:自动机

本文链接:https://www.cnblogs.com/monituihuo/articles/17610365.html

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   自动机  阅读(8)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起