2023年ICPC南京站 补题记录

A - 酷,昨日四次重现(bfs)

  • 可以发现,一个连通块中,只要有一个点可以战胜其余连通块中的所有点,那这一个连通块中的点都是获胜点
  • 所以直接暴力,对一个点bfs找到同一个连通块中的所有点,记录相对位移,然后判断其他点能不能在某些相对位移时输即可
#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<PII, int> PIII;
typedef pair<int, pair<int, bool>> PIIB;
typedef pair<PII, PII> PIIII;

const int N = 1e3 + 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 dx[] = {0, 0, -1, 1}, dy[] = {1, -1, 0, 0};

void solve()
{
	int n, m; cin >> n >> m;
	vector<string> g(n + 1);
	for (int i = 1; i <= n; i ++ )
	{
		string s; cin >> s;
		s = " " + s;
		g[i] = s;
	}
	int ans = 0, idx = 0;
	vector<vector<int>> st(n + 1, vector<int>(m + 1));
	vector<PII> pos;
	auto bfs = [&](int x, int y)
	{
		queue<PII> q;
		q.push({x, y});
		st[x][y] = ++ idx;
		while (q.size())
		{
			auto t = q.front();
			q.pop();
			int xx = t.first, yy = t.second;
			pos.push_back({xx - x, yy - y});
			for (int i = 0; i < 4; i ++ )
			{
				int nx = xx + dx[i], ny = yy + dy[i];
				if (nx <= 0 || nx > n || ny <= 0 || ny > m) continue;
				if (st[nx][ny] || g[nx][ny] != '.') continue;
				st[nx][ny] = idx;
				q.push({nx, ny});
			}
		}
	};
	for (int i = 1; i <= n; i ++ )
	{
		for (int j = 1; j <= m; j ++ )
		{
			if (st[i][j] || g[i][j] != '.') continue;
			pos.clear();
			bfs(i, j);
			bool flag = true;
			for (int r = 1; r <= n && flag; r ++ )
			{
				for (int c = 1; c <= m && flag; c ++ )
				{
					if (st[r][c] == idx || g[r][c] != '.') continue;
					bool ok = true;
					for (auto t : pos)
					{
						int nx = r + t.first, ny = c + t.second;
						if (nx <= 0 || nx > n || ny <= 0 || ny > m || g[nx][ny] != '.')
						{
							ok = false;
							break;
						}
					}
					if (ok) flag = false;
				}
			}
			if (flag) ans += pos.size();
		}
	}
	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;
}

C - 原根(数论)

  • 不会数学,抄一下队友的码
#include<iostream>
#include<cstring>
#include<cmath>
#include<cstdio>
#include<vector>
#include<map>
#include<algorithm>
#include<queue>
#include <iomanip>
#include<random>

using namespace std;
typedef long long LL;
typedef __int128 i128;
typedef unsigned long long ULL;
typedef double db;
#define int long long
int n , m , p;

void Asuka()
{
	cin >> p >> m;
	if(m < p){
		int res = 0;
		if((1 ^ (p - 1)) <= m){
			res ++;
		}
		if(((p + 1) ^ (p - 1)) <= m)res ++;
		if(((p*2+1) ^ (p - 1)) <= m)res ++;
		cout << res << '\n';
		return;
	}
	int res = (m - p + 1 - 2) / p + 1;
	// cout << res << '\n';
	int ans = res;
	for(int num = res * p + 1;num < (res + 3) * p + 1;num += p){
		if((num ^ (p - 1)) <= m)ans ++;
	}
	cout << ans << endl;
	return;
}	

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

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

F - 等价重写(思维)

  • 一开始提出一种很蠢的拓扑建图做法,然后队友说判断一下相邻两个能不能交换就好了,于是直接过了
#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;

void solve()
{
    int n, m; cin >> n >> m;
	vector<vector<int>> op(n + 1);
	for (int i = 1; i <= n; i ++ )
	{
		int x; cin >> x;
		while (x -- )
		{
			int pos; cin >> pos;
			op[i].push_back(pos);
		}
	}
    vector<bool> st(m + 1);
    vector<int> cnt(m + 1);

    for (auto t : op[n]) cnt[t] ++ ;

    bool flag = false;
	for (int i = n - 1; i >= 1; i -- )
    {
        bool flag = true;
        for (auto t : op[i])
        {
            if (st[t]) continue;
            cnt[t] ++ ;
            if (cnt[t] > 1) flag = false;
        }
        for (auto t : op[i + 1])
        {
            if (st[t]) continue;
            cnt[t] -- ;
            st[t] = true;
        }
        if (flag)
        {
            cout << "Yes\n";
            for (int j = 1; j <= i - 1; j ++ ) cout << j << ' ';
            cout << i + 1 << ' ' << i;
            for (int j = i + 2; j <= n; j ++ ) cout << ' ' << j;
            cout << '\n';
            return;
        }
    }
    cout << "No\n";
}

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

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

G - 背包(思维+01背包)

  • 依次考虑前 i i i 个位置,对前 i i i 个位置 01背包,后面的免费取 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 = 1010;
const int maxn = 1e6 + 10;
const int mod = 1e9 + 7;
const int mod1 = 954169327;
const int mod2 = 906097321;
const int INF = 0x3f3f3f3f3f3f3f3f;

void solve()
{
	int n, m, k; cin >> n >> m >> k;
	vector<PII> a(n + 1);
	for (int i = 1; i <= n; i ++ ) cin >> a[i].first >> a[i].second;
	sort(a.begin() + 1, a.end());
	priority_queue<int, vector<int>, greater<int>> pq;
	vector<int> g(n + 2);
	g[n + 1] = 0;
	int sum = 0;
	for (int i = n; i >= 1; i -- )
	{
		sum += a[i].second;
		pq.push(a[i].second);
		if (pq.size() > k)
		{
			sum -= pq.top();
			pq.pop();
		}
		g[i] = sum;
	}
	vector<int> dp(m + 1);
	int ans = g[1];
	for (int i = 1; i <= n; i ++ )
	{
		for (int j = m; j >= a[i].first; j -- )
		{
			dp[j] = max(dp[j], dp[j - a[i].first] + a[i].second);
			ans = max(ans, dp[j] + g[i + 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();
	}
}

I - 计数器(签到)

#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;

void solve()
{
    int n, m; cin >> n >> m;
	vector<PII> a(m + 1);
	for (int i = 1; i <= m; i ++ ) cin >> a[i].first >> a[i].second;
	sort(a.begin() + 1, a.end());
	int num = 0, op = 0;
	for (int i = 1; i <= m; i ++ )
	{
		int cnt = a[i].first - op;
		if (cnt == 0)
		{
			if (num == a[i].second) continue;
			else
			{
				cout << "No\n";
				return;
			}
		}
		if (a[i].second == 0)
		{
			num = 0;
			op = a[i].first;
		}
		else if (a[i].second <= cnt - 1)
		{
			num = a[i].second;
			op = a[i].first;
		}
		else
		{
			if (num + cnt == a[i].second)
			{
				num = a[i].second;
				op = a[i].first;
			}
			else
			{
				cout << "No\n";
				return;
			}
		}
	} 
	cout << "Yes\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 - 电梯(贪心+模拟)

  • 从高楼层往低楼层考虑,先放2的,放完了就放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 = 100;
const int mod = 998244353;
const int mod1 = 954169327;
const int mod2 = 906097321;
const int INF = 0x3f3f3f3f3f3f3f3f;

int mp[N], ump[N];

void solve()
{
    int n, k; cin >> n >> k;
    vector<int> c(n + 1), w(n + 1), f(n + 1), tt;
    int maxx = 0;
    for (int i = 1; i <= n; i ++ )
    {
        cin >> c[i] >> w[i] >> f[i];
        tt.push_back(f[i]);
    }
    sort(tt.begin(), tt.end());
    tt.erase(unique(tt.begin(), tt.end()), tt.end());
    for (int i = 0; i < tt.size(); i ++ )
    {
        mp[tt[i]] = i + 1;
        ump[i + 1] = tt[i];
    }
    for (int i = 1; i <= n; i ++ )
    {
        f[i] = mp[f[i]];
        maxx = max(maxx, f[i]);
    }
    vector<vector<int>> cnt(maxx + 1, vector<int>(3));
    for (int i = 1; i <= n; i ++ ) cnt[f[i]][w[i]] += c[i];
    int ans = 0, yu = 0;
    bool flag = false;
    for (int i = maxx; i >= 1; i -- )
    {
        if (flag && cnt[i][1] != 0)
        {
            flag = false;
            cnt[i][1] -- ;
        }
        if (yu != 0)
        {
            int t1 = yu / 2; // 放多少重量为2的
            if (cnt[i][2] >= t1)
            {
                cnt[i][2] -= t1;
                yu %= 2;
            }
            else
            {
                yu -= cnt[i][2] * 2;
                cnt[i][2] = 0;
            }
            if (yu != 0)
            {
                if (cnt[i][1] >= yu)
                {
                    cnt[i][1] -= yu;
                    yu = 0;
                }
                else
                {
                    yu -= cnt[i][1];
                    cnt[i][1] = 0;
                }
            }
            if (yu == 1)
            {
                yu = 0;
                flag = true;
            }
        }
        if (cnt[i][2] != 0) // 本楼层还有重量为2的
        {
            int tmp2 = k / 2; // 一趟能运多少重量为2

            // 全是本楼层重量为2的
            int c1 = cnt[i][2] / tmp2;
            ans += c1 * ump[i];
            cnt[i][2] %= tmp2;

            if (cnt[i][2] != 0)
            {
                int wei = k - cnt[i][2] * 2; // 还能装多少重量
                cnt[i][2] = 0;
                if (wei != 0)
                {
                    if (cnt[i][1] >= wei) // 剩下的部分全装本楼层重量为1的
                    {
                        cnt[i][1] -= wei;
                        ans += ump[i];
                    }
                    else
                    {
                        wei -= cnt[i][1];
                        cnt[i][1] = 0;
                        yu += wei;
                        ans += ump[i];
                        if (yu == 1)
                        {
                            yu = 0;
                            flag = true;
                        }
                    }
                }
            }
        }
        if (cnt[i][1] != 0)
        {
            int t = cnt[i][1] / k;
            ans += t * ump[i];
            cnt[i][1] %= k;
            if (cnt[i][1] != 0)
            {
                ans += ump[i];
                yu += k - cnt[i][1];
                cnt[i][1] = 0;
            }
        }
    }
    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 - 接雨水(思维)

  • 题目将原问题转化成了
    ∑ i = 1 n ( min ⁡ ( f i , g i ) − a i ) \sum\limits_{i = 1}^n \left( \min(f_i, g_i) - a_i \right) i=1n(min(fi,gi)ai)
    我们知道 min ⁡ ( f i , g i ) \min(f_i, g_i) min(fi,gi) 可以转化成 f i + g i − max ⁡ a i f_i+g_i-\max{a_i} fi+gimaxai
    所以我们要求的答案就是
    ∑ i = 1 n f i + ∑ i = 1 n g i − n × max ⁡ a i − ∑ i = 1 n a i \sum\limits_{i = 1}^nf_i+\sum\limits_{i = 1}^ng_i-n\times \max{a_i-}\sum\limits_{i = 1}^na_i i=1nfi+i=1ngin×maxaii=1nai
  • n × max ⁡ a i n\times \max{a_i} n×maxai ∑ i = 1 n a i \sum\limits_{i = 1}^na_i i=1nai 很好求,问题就转化成了求 f i f_i fi g i g_i gi
  • f i f_i fi 被分成若干段,每一段的值都相同,且从左往右单调不减,所以我们可以用 set 维护,set 中记录每一段的开头下标和值,每次增加 a i a_i ai 的值时,将 a i a_i ai 后面小于 a i a_i ai 的都删掉, 维护一下这个结构就可以了
#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 = 1010;
const int maxn = 1e6 + 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);
	vector<int> ff(n + 1), gg(n + 1);
	int sum = 0, maxx = 0;
	for (int i = 1; i <= n; i ++ )
	{
		cin >> a[i];
		maxx = max(maxx, a[i]);
		sum += a[i];
	}

	auto add = [&](int pos, int x, set<PII>& st, int &sm, vector<int> &v)
	{
		v[pos] += x;
		auto it = prev(st.upper_bound({pos, INF}));
		if ((*it).second >= v[pos]) return;
		sm -= ((*next(it)).first - (*it).first) * (*it).second;
		sm += (pos - (*it).first) * (*it).second + ((*next(it)).first - pos) * v[pos];
		it = st.insert({pos, v[pos]}).first;
		while ((*next(it)).second <= v[pos])
		{
			sm -= ((*next(it)).first - pos) * v[pos] + ((*next(next(it))).first - (*next(it)).first) * (*next(it)).second;
			st.erase(next(it));
			sm += ((*next(it)).first - pos) * v[pos];
		}
	};
	int smf = 0, smg = 0;
	set<PII> f, g;
	f.insert({1, 0}), f.insert({n + 1, INF});
	g.insert({1, 0}), g.insert({n + 1, INF});
	for (int i = 1; i <= n; i ++ ) add(i, a[i], f, smf, ff), add(n - i + 1, a[i], g, smg, gg);

	int q; cin >> q;
	while (q -- )
	{
		int pos, x; cin >> pos >> x;
		a[pos] += x;
		maxx = max(maxx, a[pos]);
		sum += x;
		add(pos, x, f, smf, ff), add(n - pos + 1, x, g, smg, gg);
		cout << smf + smg - n * maxx - sum << '\n';
	}
}

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

	int t = 1;
	cin >> t;
	while (t--)
	{
		solve();
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Texcavator

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

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

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

打赏作者

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

抵扣说明:

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

余额充值