2019年山东省大学生程序设计竞赛 补题记录

A - Sekiro(签到 思维)

  • 一定能在很有限的次数内变成 0 或 1
#include <bits/stdc++.h>

using namespace std;

#define int long long
#define double long double
using i64 = long long;

typedef pair<int, int> PII;
typedef pair<int, char> PIC;
typedef pair<double, double> PDD;
typedef pair<int, PII> PIII;
typedef pair<int, pair<int, bool>> PIIB;

const int N = 1e5 + 10;
const int maxn = 1e6;
const int MAXN = 1e5 + 10;
const int mod = 1e9 + 7;
const int mod1 = 954169327;
const int mod2 = 906097321;
const int INF = 0x3f3f3f3f3f3f3f3f;

void solve()
{
    int n, k; cin >> n >> k;
	while (k -- )
	{
		n = (n + 1) / 2;
		if (n == 1 || n == 0) break;
	}
	cout << n << '\n';
}

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(图论 找前缀后缀)

  • 如果 a a a b b b 大,就连一条从 a a a 指向 b b b 的有向边,如果图中有环肯定不行,没有环就计算每个点前缀有多少个点,后缀有多少个点,前缀后缀都小于 n 2 \frac{n}{2} 2n 就可以了
#include <bits/stdc++.h>

using namespace std;

#define int long long
#define double long double
using i64 = long long;

typedef pair<int, int> PII;
typedef pair<int, char> PIC;
typedef pair<double, double> PDD;
typedef pair<int, PII> PIII;
typedef pair<int, pair<int, bool>> PIIB;

const int N = 1e5 + 10;
const int maxn = 1e6;
const int MAXN = 1e5 + 10;
const int mod = 1e9 + 7;
const int mod1 = 954169327;
const int mod2 = 906097321;
const int INF = 0x3f3f3f3f3f3f3f3f;

void solve()
{
    int n, m; cin >> n >> m;
	vector<vector<int>> g(n + 1);
	bool flag = true;
	for (int i = 1; i <= m; i ++ )
	{
		int a, b; cin >> a >> b;
		if (a == b) flag = false;
		g[a].push_back(b);
	}
	if (!flag)
	{
		for (int i = 1; i <= n; i ++ ) cout << 0;
		cout << '\n';
		return;
	}
	vector<int> from(n + 1), pre(n + 1), suf(n + 1);
	auto bfs = [&](int rt)
	{
		queue<int> q;
		q.push(rt);
		from[rt] = rt;
		while (q.size())
		{
			auto t = q.front();
			q.pop();
			for (int i = 0; i < g[t].size(); i ++ )
			{
				int j = g[t][i];
				if (j == rt) return false;
				if (from[j] == rt) continue;
				q.push(j);
				from[j] = rt;
				pre[j] ++ , suf[rt] ++ ;
			}
		}
		return true;
	};
	for (int i = 1; i <= n; i ++ )
	{
		if (!bfs(i))
		{
			for (int j = 1; j <= n; j ++ ) cout << 0;
			cout << '\n';
			return;
		}
	}
	for (int i = 1; i <= n; i ++ )
	{
		if (pre[i] <= n / 2 && suf[i] <= n / 2) cout << 1;
		else cout << 0;
	}
	cout << '\n';
}

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

    int t = 1;
    cin >> t;
    while (t--)
    {
        solve();
    }
    return 0;
}

C - Tokens on the Segments(贪心 优先队列)

  • 从小到大放到优先队列里,记录当前可以选的最小的 x x x,记作 p o s pos pos
  • 每次取出队头,看能不能取到 p o s pos pos,不能就把区间更新为 [ p o s ,   r ] [pos,\ r] [pos, r](如果不能这样更新肯定就是直接丢掉了),再存到堆里,可以就累加答案,更新 p o s pos pos
#include <bits/stdc++.h>

using namespace std;

#define int long long
#define double long double
using i64 = long long;

typedef pair<int, int> PII;
typedef pair<int, char> PIC;
typedef pair<double, double> PDD;
typedef pair<int, PII> PIII;
typedef pair<int, pair<int, bool>> PIIB;

const int N = 1e5 + 10;
const int maxn = 1e6;
const int MAXN = 1e5 + 10;
const int mod = 1e9 + 7;
const int mod1 = 954169327;
const int mod2 = 906097321;
const int INF = 0x3f3f3f3f3f3f3f3f;

void solve()
{
    int n; cin >> n;
	priority_queue<PII, vector<PII>, greater<PII>> pq;
	for (int i = 0; i < n; i ++ )
	{
		int l, r;
		cin >> l >> r;
		pq.push({l, r});
	}
	int pos = 1;
	int ans = 0;
	while (pq.size())
	{
		auto t = pq.top();
		pq.pop();

		int l = t.first, r = t.second;
		if (pos > l)
		{
			l = pos;
			if (l > r) continue;
			pq.push({l, r});
			continue;
		}
		else
		{
			ans ++ ;
			pos = l + 1;
		}
	}
	cout << ans << '\n';
}

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(签到 思维)

  • 能求出每一堆最后会剩下多少石子,一定是从多的里面拿,那看多了多少就行
#include <bits/stdc++.h>

using namespace std;

#define int long long
#define double long double
using i64 = long long;

typedef pair<int, int> PII;
typedef pair<int, char> PIC;
typedef pair<double, double> PDD;
typedef pair<int, PII> PIII;
typedef pair<int, pair<int, bool>> PIIB;

const int N = 1e5 + 10;
const int maxn = 1e6;
const int MAXN = 1e5 + 10;
const int mod = 1e9 + 7;
const int mod1 = 954169327;
const int mod2 = 906097321;
const int INF = 0x3f3f3f3f3f3f3f3f;

void solve()
{
    int n; cin >> n;
	vector<int> a(n + 1);
	int sum = 0;
	for (int i = 1; i <= n; i ++ )
	{
		cin >> a[i];
		sum += a[i];
	}
	int cnt = sum / n;
	int more = 0;
	for (int i = 1; i <= n; i ++ )
	{
		if (a[i] > cnt) more += a[i] - cnt;
	}
	cout << more << '\n';
}

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

    int t = 1;
    cin >> t;
    while (t--)
    {
        solve();
    }
    return 0;
}

E - BaoBao Loves Reading(树状数组)

  • 记录每本书上一次看的时间,如果从上一次看到这一次中间书的种类超过 k k k,就需要重新拿回来
  • 区间种类数,用树状数组维护
  • 最后后缀和计算
#include <bits/stdc++.h>

using namespace std;

#define int long long
#define double long double
using i64 = long long;

typedef pair<int, int> PII;
typedef pair<int, char> PIC;
typedef pair<double, double> PDD;
typedef pair<int, PII> PIII;
typedef pair<int, pair<int, bool>> PIIB;

const int N = 1e5 + 10;
const int maxn = 1e6;
const int MAXN = 100;
const int mod = 998244353;
const int mod1 = 954169327;
const int mod2 = 906097321;
const int INF = 0x3f3f3f3f3f3f3f3f;

int n, tree[N];

int lowbit(int x)
{
	return x & -x;
}

void add(int i, int x)
{
	while (i < N)
	{
		tree[i] += x;
		i += lowbit(i);
	}
}

int prefix_sum(int i)
{
	int presum = 0;
	while (i > 0)
	{
		presum += tree[i];
		i -= lowbit(i);
	}
	return presum;
}

int query(int l, int r)
{
	return prefix_sum(r) - prefix_sum(l - 1);
}

void solve()
{
    cin >> n;
	for (int i = 0; i < N; i ++ ) tree[i] = 0;
	vector<int> last(n + 1);
	vector<int> ans(n + 2);
	for (int i = 1; i <= n; i ++ )
	{
		int x; cin >> x;
		if (last[x] == 0) ans[n] ++ ;
		else
		{
			int tmp = query(last[x] + 1, i - 1);
			ans[tmp] ++ ;
			add(last[x], -1);
		}
		add(i, 1);
		last[x] = i;
	}
	for (int i = n; i >= 1; i -- ) ans[i] += ans[i + 1];
	for (int i = 1; i <= n; i ++ )
	{
		cout << ans[i];
		if (i != n) cout << ' ';
	}
	cout << '\n';
}

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 − 1 n-1 n1 条边,然后就没了,这题也太水了
#include <bits/stdc++.h>

using namespace std;

#define int long long
#define double long double
using i64 = long long;

typedef pair<int, int> PII;
typedef pair<int, char> PIC;
typedef pair<double, double> PDD;
typedef pair<int, PII> PIII;
typedef pair<int, pair<int, bool>> PIIB;

const int N = 1e5 + 10;
const int maxn = 1e6;
const int MAXN = 1e5 + 10;
const int mod = 1e9 + 7;
const int mod1 = 954169327;
const int mod2 = 906097321;
const int INF = 0x3f3f3f3f3f3f3f3f;

void solve()
{
    int k; cin >> k;
	string s; cin >> s;
	s = " " + s;
	int n, m; cin >> n >> m;
	for (int i = 1; i <= m; i ++ )
	{
		int x; cin >> x >> x;
	}
	int pos = m - (n - 2);
	pos %= k;
	if (pos == 0) pos = k;
	if (s[pos] == '1') cout << 2 << '\n';
	else cout << 1 << '\n';
}

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(思维)

  • 最大距离只会出现在第一次循环和最后一次循环
#include <bits/stdc++.h>

using namespace std;

#define int long long
#define double long double
using i64 = long long;

typedef pair<int, int> PII;
typedef pair<int, char> PIC;
typedef pair<double, double> PDD;
typedef pair<int, PII> PIII;
typedef pair<int, pair<int, bool>> PIIB;

const int N = 1e5 + 10;
const int maxn = 1e6;
const int MAXN = 1e5 + 10;
const int mod = 1e9 + 7;
const int mod1 = 954169327;
const int mod2 = 906097321;
const int INF = 0x3f3f3f3f3f3f3f3f;

void solve()
{
    int n, k; cin >> n >> k;
	string s;
	cin >> s;
	int x = 0, y = 0;
	vector<PII> maxx(4); // 左上 左下 右上 右下
	int ans = 0;
	for (auto t : s)
	{
		if (t == 'U') y ++ ;
		else if (t == 'D') y -- ;
		else if (t == 'L') x -- ;
		else x ++ ;
		ans = max(ans, llabs(x) + llabs(y));
	}
	x = x * (k - 1);
	y = y * (k - 1);
	for (auto t : s)
	{
		if (t == 'U') y ++ ;
		else if (t == 'D') y -- ;
		else if (t == 'L') x -- ;
		else x ++ ;
		ans = max(ans, llabs(x) + llabs(y));
	}
	cout << ans << '\n';
}

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 a a 是奇数答案为 1 1 1 (不会证明)
  • a a a 是偶数的时候:
    • 如果 x ≥ p x\geq p xp,那 a x a^x ax 一定有一个因数是 2 x 2^x 2x,也就一定有一个因数是 2 p 2^p 2p,所以 a x m o d    2 p = 0 a^x\mod 2^p=0 axmod2p=0,所以现在是要让 x a m o d    2 p = 0 x^a\mod 2^p=0 xamod2p=0,设 x x x 中有 k k k 2 2 2,那么 k a ≥ p ka\geq p kap,所以 k ≥ ⌈ p a ⌉ = k ′ k\geq \lceil \frac{p}{a}\rceil=k' kap=k,也就是在 [ p ,   2 p ] [p,\ 2^p] [p, 2p] 2 k ′ 2^{k'} 2k 的倍数
    • 否则,枚举计算
#include <bits/stdc++.h>

using namespace std;

#define int long long
#define double long double
using i64 = long long;

typedef pair<int, int> PII;
typedef pair<int, char> PIC;
typedef pair<double, double> PDD;
typedef pair<int, PII> PIII;
typedef pair<int, pair<int, bool>> PIIB;

const int N = 1e5 + 10;
const int maxn = 1e6;
const int MAXN = 100;
const int mod = 998244353;
const int mod1 = 954169327;
const int mod2 = 906097321;
const int INF = 0x3f3f3f3f3f3f3f3f;

int pow(int a, int n, int p)
{
    int ans = 1;
    while (n)
    {
        if (n & 1) ans = ans * a % p;
        a = a * a % p;
        n >>= 1;
    }
    return ans;
}

void solve()
{
    int a, p; cin >> a >> p;
	if (a & 1) cout << 1 << '\n';
	else
	{
		int ans = 0;
		for (int x = 1; x < p; x ++ )
		{
			if (pow(a, x, (1 << p)) == pow(x, a, (1 << p))) ans ++ ;
		}
		int k = (p + a - 1) / a;
		ans += (1 << (p - k)) - (p - 1) / (1 << k);
		cout << ans << '\n';
	}
}

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

    int t = 1;
    cin >> t;
    while (t--)
    {
        solve();
    }
    return 0;
}

M - Calandar(签到)

  • 每月每天的星期都是一样的
#include <bits/stdc++.h>

using namespace std;

#define int long long
#define double long double
using i64 = long long;

typedef pair<int, int> PII;
typedef pair<int, char> PIC;
typedef pair<double, double> PDD;
typedef pair<int, PII> PIII;
typedef pair<int, pair<int, bool>> PIIB;

const int N = 1e5 + 10;
const int maxn = 1e6;
const int MAXN = 1e5 + 10;
const int mod = 1e9 + 7;
const int mod1 = 954169327;
const int mod2 = 906097321;
const int INF = 0x3f3f3f3f3f3f3f3f;

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

void solve()
{
    int a1, a2, a3;
	string s;
	cin >> a1 >> a2 >> a3 >> s;
	int b1, b2, b3;
	cin >> b1 >> b2 >> b3;
	int a4;
	if (s[0] == 'M') a4 = 1;
	else if (s[0] == 'T' && s[1] == 'u') a4 = 2;
	else if (s[0] == 'W') a4 = 3;
	else if (s[0] == 'T' && s[1] == 'h') a4 = 4;
	else a4 = 5;
	if (a3 <= b3)
	{
		while (a3 != b3)
		{
			a4 ++ ;
			if (a4 == 6) a4 = 1;
			a3 ++ ;
		}
	}
	else
	{
		while (a3 != b3)
		{
			a4 -- ;
			if (a4 == 0) a4 = 5;
			a3 -- ;
		}
	}
	cout << tmp[a4] << '\n';
}

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

    int t = 1;
    cin >> t;
    while (t--)
    {
        solve();
    }
    return 0;
}

L - Flipping Game(dp)

  • 先把末尾状态全变成 0 0 0
  • d p [ i ] [ j ] dp[i][j] dp[i][j] 表示前 i i i 个操作后,还有 j j j 盏灯亮着
  • 可以由 d p [ i ] [ j ] dp[i][j] dp[i][j],转移第 i + 1 i+1 i+1 个状态,如果在第 i + 1 i+1 i+1 个操作熄灭了 x x x 盏灯,也就是点亮了 m − x m-x mx 盏灯
  • d p [ i + 1 ] [ j − x + ( m − x ) ] + = d p [ i ] [ j ] × C j x × C n − j m − x dp[i+1][j-x+(m-x)]+=dp[i][j]\times C_j^x\times C_{n-j}^{m-x} dp[i+1][jx+(mx)]+=dp[i][j]×Cjx×Cnjmx
#include <bits/stdc++.h>

using namespace std;

#define int long long
#define double long double
using i64 = long long;

typedef pair<int, int> PII;
typedef pair<int, char> PIC;
typedef pair<double, double> PDD;
typedef pair<int, PII> PIII;
typedef pair<int, pair<int, bool>> PIIB;

const int N = 1e5 + 10;
const int maxn = 1e6;
const int MAXN = 100;
const int mod = 998244353;
const int mod1 = 954169327;
const int mod2 = 906097321;
const int INF = 0x3f3f3f3f3f3f3f3f;

int C[110][110];

void init()
{
	for (int i = 0; i <= MAXN; i ++ )
	{
        C[i][0] = 1;
        for (int j = 1; j <= i; j ++ )
			C[i][j] = (C[i - 1][j - 1] + C[i - 1][j]) % mod;
    }
}

void solve()
{
    int n, k, m; cin >> n >> k >> m;
	string s, t; cin >> s >> t;
	int cnt = 0;
	for (int i = 0; i < n; i ++ )
	{
		if (t[i] != '0')
		{
			t[i] = '0';
			if (s[i] == '1') s[i] = '0';
			else s[i] = '1';
		}
		if (s[i] != t[i]) cnt ++ ;
	}
	vector<vector<int>> dp(k + 1, vector<int>(n + 1));
	dp[0][cnt] = 1;
	for (int i = 0; i < k; i ++ )
	{
		for (int j = 0; j <= n; j ++ )
		{
			for (int x = 0; x <= j && x <= m; x ++ )
			{
				if (n - j < m - x) continue;
				dp[i + 1][j - x + (m - x)] = (dp[i + 1][j - x + (m - x)] + dp[i][j] * C[j][x] % mod * C[n - j][m - x] % mod) % mod;
			}
		}
	}
	cout << dp[k][0] << '\n';
}

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

	init();
    int t = 1;
    cin >> t;
    while (t--)
    {
        solve();
    }
    return 0;
}

  • 22
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Texcavator

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值