Loading

The 10th Shandong Provincial Collegiate Programming Contest



A - Sekiro

题意

初始有\(n\)个金币,死了\(m\)次,死一次\(n = \lceil \frac n 2 \rceil\)。求最后的金币数。

思路

模拟。

代码

点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define int long long

void solve()
{
	int n, m;
	cin >> n >> m;
	while (m-- && n > 1)
	{
		n = (n + 1) >> 1;
	}
	cout << n << endl;
}

signed main()
{
	ios::sync_with_stdio(false);
	cin.tie(0), cout.tie(0);

	int T = 1;
	cin >> T;
	while (T--)
	{
		solve();
	}

	return 0;
}

B - Median

题意

\(n\)个数(\(n\)是奇数),\(m\)对关系(\(u v\)表示\(u > v\)),对于第\(i\)个元素,给每个元素赋值,能使它成为中位数就输出\(1\),否则输出\(0\)

思路

一条关系可以看作一条有向边,由大的指向小的,得到一张有向图,先判断有无环,有环说明情况不存在全为\(0\),可用\(bfs\)\(dfs\)判断,同时记录该点的前继和后继,若该点为中位数,说明该点的前继和后继都不超过\(\frac n 2\)

代码

点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define int long long

const int mxn = 110;

int n, m, cnt;
vector<int>g1[mxn], g2[mxn];
int up[mxn], low[mxn], deg[mxn], vis[mxn];

void dfs1(int u, int fa) 
{
    vis[u] = 1;
    for (auto v : g2[u]) 
    {
        if (!vis[v]) 
        {
            cnt++;
            dfs1(v, u);
        }
    }
}

void dfs2(int u, int fa) 
{
    vis[u] = 1;
    for (auto v : g1[u])
    {
        if (!vis[v])
        {
            cnt++;
            dfs2(v, u);
        }
    }
}

bool topo() {
    cnt = 0;
    queue<int>q;
    for (int i = 1; i <= n; i++) 
    {
        if (deg[i] == 0)
        {
            q.push(i);
        }
    }
    while (!q.empty()) 
    {
        int u = q.front();
        q.pop();
        cnt++;
        for (auto v : g1[u])
        {
            if (--deg[v] == 0)
            {
                q.push(v);
            }
        }
    }
    return cnt == n;
}

void init() 
{
    for (int i = 1; i <= n; i++) 
    {
        g1[i].clear();
        g2[i].clear();
        deg[i] = 0;
        up[i] = 0;
        low[i] = 0;
    }
}


void solve()
{
    cin >> n >> m;
    init();
    for (int i = 1; i <= m; i++) 
    {
        int u, v;
        cin >> u >> v;
        g1[u].push_back(v);
        g2[v].push_back(u);
        deg[v]++;
    }
    if (!topo()) 
    {
        for (int i = 1; i <= n; i++) 
        {
            putchar('0');
        }
        putchar('\n');
        return;
    }
    for (int i = 1; i <= n; i++) 
    {
        for (int j = 1; j <= n; j++)
        {
            vis[j] = 0;
        }
        cnt = 0;
        dfs1(i, -1);
        up[i] = cnt;
        for (int j = 1; j <= n; j++) 
        {
            vis[j] = 0;
        }
        cnt = 0;
        dfs2(i, -1);
        low[i] = cnt;
    }
    for (int i = 1; i <= n; i++) 
    {
        if (up[i] < (n + 1) / 2 && low[i] < (n + 1) / 2) 
        {
            putchar('1');
        }
        else 
        {
            putchar('0');
        }
    }
    putchar('\n');
}

signed main() 
{
    ios::sync_with_stdio(0);
    cin.tie(0), cout.tie(0);

    int T;
    cin >> T;
    while (T--)
    {
        solve();
    }

    return 0;
}


C - Tokens on the Segments

题意

\(n\)条线段,其中第\(i\)段的端点是\((l_i, i)\)\((r_i, i)\),在平面的整数点放标记,但是标记的\(x\)坐标必须彼此不同。问最多有多少条线段上有标记。

思路

按如下方法将线段存入小根堆:左端点靠前的在前,左端点一样的,右端点靠前的在前。从最左边的线段的左端点开始计数,用指针记录当前位置。指针右移,同时更新其他线段的左端点(因为标记的\(x\)不能相同),到新的线段就\(ans++\),当前位置没有线段就直接移动到下一条线段。

代码

点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define int long long

struct edge
{
	int l, r;
	bool operator < (const edge& a) const
	{
		if (l == a.l)
		{
			return r > a.r;
		}
		return l > a.l;
	}
};

void solve()
{
	int n;
	cin >> n;
	priority_queue<edge, vector<edge>> q; // 小根堆
	for (int i = 0; i < n; i++)
	{
		int l, r;
		cin >> l >> r;
		q.push({ l,r });
	}
	int now = 1, ans = 0; // 当前可以标记的位置
	while (!q.empty())
	{
		int l = q.top().l;
		int r = q.top().r;
		q.pop();
		if (r >= now) // 右端点>=now就可以标记,且尽量往左标—,所以要更新左端点
		{
			ans++;
			if (l < now) // 标记处在线段左边(与上一条之间有空)
			{
				now = l + 1;
			}
			else
			{
				now++;
			}
		}
		while (q.size() && q.top().l == l) // 更新左端点
		{
			edge t = q.top();
			q.pop();
			t.l++; // 前推1
			if (t.l <= t.r) // 仍然是线段(或者点)
			{
				q.push(t);
			}
		}
	}
	cout << ans << endl;
}


signed main()
{
	ios::sync_with_stdio(false);
	cin.tie(0), cout.tie(0);

	int T = 1;
	cin >> T;
	while (T--)
	{
		solve();
	}

	return 0;
}

D - Stones in the Bucket

题意

\(n\)个桶,第\(i\)个桶里有\(a_i\)个石头。两种操作:从非空同种一走一个石头、把一个桶里的石头移到另一个桶里。问使得所有桶里石头数相同所需的最小操作数。

思路

模拟。

代码

点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define int long long

void solve()
{
	int n, sum = 0;
	cin >> n;
	vector<int> v(n);
	for (int i = 0; i < n; i++)
	{
		cin >> v[i];
		sum += v[i];
	}
	if (n == 1)
	{
		cout << 0 << endl;
		return;
	}
	int ans = sum % n; // 剩下的
	sum /= n; // 平均分
	for (int i = 0; i < n; i++)
	{
		if (v[i] != sum && v[i] < sum) // 少的多的看一半就行
		{
			ans += (sum - v[i]);
		}
	}
	cout << ans << endl;
}

signed main()
{
	ios::sync_with_stdio(false);
	cin.tie(0), cout.tie(0);

	int T = 1;
	cin >> T;
	while (T--)
	{
		solve();
	}

	return 0;
}

F - Game on a Graph

题意

给定\(n\)个顶点\(m\)条边的简单连通图,\(k\)个人已知分队,轮流删边,使得图不连通的队伍输。两个队伍用最佳策略游戏,问哪队赢。

思路

连通图至少有\(n-1\)条边,也就是说谁能删\(m-(n-1)\)条边。

代码

点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define int long long

void solve()
{
	int n, m, k;
	string s;
	cin >> k >> s >> n >> m;
	for (int i = 0; i < m; i++)
	{
		int u, v;
		cin >> u >> v;
	}
	int idx = (m - n + 1) % k;
	cout << (s[idx] == '1' ? '2' : '1') << endl;
}


signed main()
{
	ios::sync_with_stdio(false);
	cin.tie(0), cout.tie(0);

	int T = 1;
	cin >> T;
	while (T--)
	{
		solve();
	}

	return 0;
}

H - Wandering Robot

题意

一个在\((0,0)\)机器人每次能够上/下/左/右移动一个单位,用\(U/D/L/R\)表示。已知长度为\(n\)的操作序列,以及重复操作了\(k\)次,求移动过程中机器人到点\((0,0)\)的曼哈顿距离的最大值。
曼哈顿距离:\(|x1−x2|+|y1−y2|\)

思路

答案一定在第一次操作或第\(k\)次操作中,因为如果第一轮结束导致答案增大,那就会一直增大直至第\(k\)次操作结束;如果减小,之后也会一直减小。

代码

点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define int long long

int n, k;
string cmd;

void move(int& x, int& y, int& ans)
{
	for (int i = 0; i < n; i++)
	{
		switch (cmd[i])
		{
		case 'U':
			y++;
			break;
		case 'D':
			y--;
			break;
		case 'L':
			x--;
			break;
		case 'R':
			x++;
			break;
		default:
			break;
		}
		ans = max(ans, abs(x) + abs(y));
	}
}

void solve()
{
	cin >> n >> k >> cmd;
	int x = 0, y = 0, ans = 0;
	move(x, y, ans);
	int kx = (k - 1) * x, ky = (k - 1) * y; // (k - 1)次操作后的坐标
	move(kx, ky, ans);
	cout << ans << endl;
}


signed main()
{
	ios::sync_with_stdio(false);
	cin.tie(0), cout.tie(0);

	int T = 1;
	cin >> T;
	while (T--)
	{
		solve();
	}

	return 0;
}

K - Happy Equation

题意

给定\(a\)\(p\),问有多少个\(x\)满足\(a^x \equiv x^a \ mod \ 2^p\)

思路

打表发现,当\(x\)为奇数时,答案为\(1\)。那就只用考虑\(x\)是偶数的情况:当\(x \le p\),直接枚举;当\(x > p\),此时\(a^x \ mod \ 2^p \equiv 0\),只要保证\(x^a \ mod \ 2^p = 0\)即可,即求\(2^p\)\(2^{p/a}\)的多少倍。

代码

点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define int long long

int qp(int base, int x, int mod)
{
	int res = 1;
	while (x)
	{
		if (x & 1)
		{
			res *= base;
			res %= mod;
		}
		x >>= 1;
		base *= base;
		base %= mod;
	}
	return res;
}

void solve()
{
	int a, p;
	cin >> a >> p;
	if (a & 1)
	{
		cout << 1 << endl;
		return;
	}
	int mod = (1LL << p);
	int ans = 0;
	for (int i = 1; i <= p; i++)
	{
		if (qp(a, i, mod) == qp(i, a, mod))
		{
			ans++;
		}
	}
	int t = p / a + (p % a != 0);
	int l = 1LL << t;
	ans += (mod / l - p / l);
	cout << ans << endl;;
}

signed main()
{
	ios::sync_with_stdio(0);
	cin.tie(0), cout.tie(0);

	int T = 1;
	cin >> T;
	while (T--)
	{
		solve();
	}

	return 0;
}


M - Calandar

题意

定义一年有\(12\)个月,每月\(30\)天,每周\(5\)天(周五之后是周一)。已知今天是\(y_1\)\(m_1\)\(d_1\)日和周几,求\(y_2\)\(m_2\)\(d_2\)日是周几。

思路

算日期差值后取模即可。

代码

点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define int long long

string week[] = { "Monday", "Tuesday", "Wednesday", "Thursday", "Friday" };

void solve()
{
	int y1, y2, m1, m2, d1, d2;
	string w;
	cin >> y1 >> m1 >> d1 >> w >> y2 >> m2 >> d2;
	int num1 = y1 * 12 * 30 + m1 * 30 + d1;
	int num2 = y2 * 12 * 30 + m2 * 30 + d2;
	int dt = (num2 - num1) % 5;
	int id = 0;
	for (int i = 0; i < 5; i++)
	{
		if (w == week[i])
		{
			id = i;
			break;
		}
	}
	cout << week[(id + dt + 5) % 5] << endl;
}


signed main()
{
	ios::sync_with_stdio(false);
	cin.tie(0), cout.tie(0);

	int T = 1;
	cin >> T;
	while (T--)
	{
		solve();
	}

	return 0;
}


比赛链接 https://codeforces.com/gym/104459

posted @ 2024-10-06 22:51  _SeiI  阅读(7)  评论(0编辑  收藏  举报