2024.4.22-4.28 训练记录(28)

ATC - abc350

A - Past ABCs

输出题,因为没注意0吃了一发

#include <bits/stdc++.h>

using namespace std;

#define int long long
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 = 2e5 + 10;
const int mod = 1e9 + 7;
const int maxn = 1e6 + 10;
const int mod1 = 954169327;
const int mod2 = 906097321;
const int INF = 0x3f3f3f3f3f3f3f3f;

void solve()
{
	string s;
    cin >> s;
    int tmp = (s[3] - '0') * 100 + (s[4] - '0') * 10 + s[5] - '0';
    if (tmp < 350 && tmp != 316 && tmp > 0) cout << "Yes\n";
    else cout << "No\n";
}

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

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

B - Dentist Aoki

好歹毒的一题,判断一下每个洞处理次数是奇数还是偶数

#include <bits/stdc++.h>

using namespace std;

#define int long long
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 = 2e5 + 10;
const int mod = 1e9 + 7;
const int maxn = 1e6 + 10;
const int mod1 = 954169327;
const int mod2 = 906097321;
const int INF = 0x3f3f3f3f3f3f3f3f;

void solve()
{
	int n, q;
    cin >> n >> q;
    map<int, int> mp;
    for (int i = 0; i < q;i  ++ )
    {
        int x; cin >> x;
        mp[x] ++ ;
    }
    for (auto t : mp)
    {
        if (t.second % 2 != 0) n -- ;
    }
    cout << n << '\n';
}

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

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

C - Sort

从前往后每次贪心去换

#include <bits/stdc++.h>

using namespace std;

#define int long long
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 = 2e5 + 10;
const int mod = 1e9 + 7;
const int maxn = 1e6 + 10;
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> idx(n + 1);
    for (int i = 1; i <= n; i ++ )
    {
        cin >> a[i];
        idx[a[i]] = i;
    }
    vector<PII> ans;
    for (int i = 1; i <= n; i ++ )
    {
        if (a[i] == i) continue;
        ans.push_back({i, idx[i]});
        int p1 = a[i], p2 = i;
        int q1 = i, q2 = idx[i];
        swap(a[q1], a[q2]);
        idx[p1] = q2, idx[p2] = q1;
    }
    cout << ans.size() << '\n';
    for (auto t : ans)
    {
        cout << t.first << ' ' << t.second << '\n';
    }
}

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

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

D - New Friends(完全图边数)

其实就是问完全图的边数,因为最终情况就是完全图

#include <bits/stdc++.h>

using namespace std;

#define int long long
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 = 2e5 + 10;
const int mod = 1e9 + 7;
const int maxn = 1e6 + 10;
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);
	for (int i = 0; i < m; i ++ )
	{
		int a, b;
		cin >> a >> b;
		g[a].push_back(b);
		g[b].push_back(a);
	}
	vector<bool> st(n + 1);
	int ans = 0, sum = 0, cnt = 0;
	function<void(int)> dfs = [&](int u)
	{
		if (st[u]) return;
		st[u] = true;
		sum += g[u].size();
		cnt ++ ;
		for (int i = 0; i < g[u].size(); i ++ )
		{
			int j = g[u][i];
			if (st[j]) continue;
			dfs(j);
		}
	};
	for (int i = 1; i <= n; i ++ )
	{
		sum = 0, cnt = 0;
		if (!st[i])
		{
			dfs(i);
			int res = (1 + cnt - 1) * (cnt- 1) / 2;
			ans += res - sum / 2;
		}
	}
	cout << ans << '\n';
}

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

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

E - Toward 0(记忆化搜索)

应该是第一次做到的记忆化搜索?分治的思想,又有点类似dp的状态转移,因为每一步的贪心无法得到全局最优解,所以通过递归解决每次是选择第一种方案还是第二种

#include <bits/stdc++.h>

using namespace std;

#define int long long
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 = 2e5 + 10;
const int mod = 1e9 + 7;
const int maxn = 1e6 + 10;
const int mod1 = 954169327;
const int mod2 = 906097321;
const int INF = 0x3f3f3f3f3f3f3f3f;

void solve()
{
	int n, a, x, y;
	cin >> n >> a >> x >> y;
	map<int, double> dp;
	function<double(int)> dfs = [&](int u)
	{
		if (u == 0) return 0.0;
		if (dp[u]) return dp[u];
		double ans1 = dfs(u / a) + x;
		double ans2 = y * 6.0 / 5.0;
		for (int i = 2; i <= 6; i ++ ) ans2 += dfs(u / i) / 5.0;
		dp[u] = min(ans1, ans2);
		return dp[u];
	};
	printf("%.8lf", dfs(n));
}

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

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

F - Transpose(文艺平衡树)

笑死我了让我碰上一道F,看一眼很明显的文艺平衡树板题,直接抄了个板子来改改过了

#include <bits/stdc++.h>

using namespace std;

#define int long long
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 = 5e5 + 10;
const int mod = 1e9 + 7;
const int maxn = 1e6 + 10;
const int mod1 = 954169327;
const int mod2 = 906097321;
const int INF = 0x3f3f3f3f3f3f3f3f;

int root, idx; // 分别表示根结点编号和当前用到哪个结点
int val[N]; // 结点权值
int pri[N]; // 结点优先级
int sz[N]; // 结点子树大小
int ch[N][2]; // 结点左右儿子
int tag[N]; // 翻转标记
int lz[N]; // 大小写标记
	string s;

void pushup(int u) // 更新结点u信息
{
	sz[u] = sz[ch[u][0]] + sz[ch[u][1]] + 1;
}

void pushdown(int u)
{
	if (lz[u])
	{
		lz[ch[u][0]] ^= 1;
		lz[ch[u][1]] ^= 1;
		if (s[val[u]] >= 'a' && s[val[u]] <= 'z') s[val[u]] += 'A' - 'a';
		else if (s[val[u]] >= 'A' && s[val[u]] <= 'Z') s[val[u]] += 'a' - 'A';
		lz[u] = 0;
	}
	if (tag[u])
	{
		swap(ch[u][0], ch[u][1]);
		tag[ch[u][0]] ^= 1;
		tag[ch[u][1]] ^= 1;
		tag[u] = 0;
	}
}

void split(int u, int x, int& lt, int& rt) // 把treap分成小于等于x和大于x的两个部分
{
	if (u == 0)
	{
		lt = rt = 0;
		return;
	}
	pushdown(u);
	if (sz[ch[u][0]] + 1 <= x) // 当前点小于x,说明分界点在右儿子
	{
		lt = u;
		split(ch[u][1], x - sz[ch[u][0]] - 1, ch[u][1], rt);
	}
	else // 当前点大于x,说明分界点在左儿子
	{
		rt = u;
		split(ch[u][0], x, lt, ch[u][0]);
	}
	pushup(u); // 更新结点u信息
}

int merge(int lt, int rt) // 合并根结点编号为lt和rt的两棵treap
{
	if (lt == 0 || rt == 0) return lt + rt;
	if (pri[lt] > pri[rt]) // lt的优先级比rt大 就把rt合并到lt的右子树
	{
		pushdown(lt);
		ch[lt][1] = merge(ch[lt][1], rt);
		pushup(lt);
		return lt;
	}
	else // rt的优先级比lt大 就把lt合并到rt的左子树
	{
		pushdown(rt);
		ch[rt][0] = merge(lt, ch[rt][0]);
		pushup(rt);
		return rt;
	}
}

void getnode(int x) // 创建权值为x的新结点
{
	sz[++ idx] = 1;
	ch[idx][0] = ch[idx][1] = 0;
	val[idx] = x;
	tag[idx] = 0;
	pri[idx] = rand(); // 优先值取随机数保证树形状随机
}

void insert(int x, char c) // 将权值为x的新结点插入treap
{
	int lt, rt;
	split(root, x, lt, rt); // 先把原treap分成小于等于x和大于x两个部分
	getnode(x); // 创建值为x的结点
	root = merge(merge(lt, idx), rt); // 先合并小于等于x的子树和新结点 再将其与大于x的子树合并
	return; // 返回新结点编号
}

void dfs(int u)
{
	if (!u) return;
	pushdown(u);
	dfs(ch[u][0]);
	if ((s[val[u]] >= 'a' && s[val[u]] <= 'z') || (s[val[u]] >= 'A' && s[val[u]] <= 'Z')) cout << s[val[u]];
	dfs(ch[u][1]);
}

void solve()
{
	cin >> s;
	int n = s.size();
	s = " " + s;
	for (int i = 1; i <= n; i ++ ) insert(i, s[i]);
	stack<int> stk;
	for (int i = 1; i <= n; i ++ )
	{
		if (s[i] == '(') stk.push(i);
		else if (s[i] == ')')
		{
			int l = stk.top();
			stk.pop();
			int r = i;
			int lt, rt, md;
			split(root, r, lt, rt);
			split(lt, l - 1, lt, md);
			tag[md] ^= 1;
			lz[md] ^= 1;
			root = merge(merge(lt, md), rt);
		}
	}
	dfs(root);
}

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

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

ATC - abc349

E - Weighted Tic-Tac-Toe(博弈+搜索)

如果局部最优解无法推出全局最优解,当前最优的策略可能会让之后处于较劣情况,那就赶紧抛开贪心的想法!

再看一眼范围也不大,于是直接搜索

#include <bits/stdc++.h>

using namespace std;

#define int long long
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 = 2e5 + 10;
const int mod = 1e9 + 7;
const int maxn = 1e6 + 10;
const int mod1 = 954169327;
const int mod2 = 906097321;
const int INF = 0x3f3f3f3f3f3f3f3f;

void solve()
{
	vector<vector<int>> g(4, vector<int>(4)), cl(4, vector<int>(4));
	for (int i = 1; i <= 3; i ++ )
		for (int j = 1; j <= 3; j ++ )
			cin >> g[i][j];

	vector<int> score(3);

	auto check = [&]()
	{
		for (int i = 1; i <= 3; i ++ )
		{
			if (cl[i][1] != 0 && cl[i][1] == cl[i][2] && cl[i][1] == cl[i][3]) return cl[i][1];
			if (cl[1][i] != 0 && cl[1][i] == cl[2][i] && cl[1][i] == cl[3][i]) return cl[1][i];
		}
		if (cl[1][1] != 0 && cl[1][1] == cl[2][2] && cl[1][1] == cl[3][3]) return cl[1][1];
		if (cl[1][3] != 0 && cl[1][3] == cl[2][2] && cl[2][2] == cl[3][1]) return cl[1][3];

		for (int i = 1; i <= 3; i ++ )
			for (int j = 1; j <= 3; j ++ )
				if (cl[i][j] == 0) return (int)0;
		return score[1] > score[2] ? (int)1 : (int)2;
	};

	function<int(int)> dfs = [&](int op) // op = 1说明第一个人 op = 0说明第二个人
	{
		int res = check();
		if (res) return res % 2;
		for (int i = 1; i <= 3; i ++ )
		{
			for (int j = 1; j <= 3; j ++ )
			{
				if (cl[i][j]) continue;
				score[op] += g[i][j];
				cl[i][j] = op;
				int res = dfs(op == 1 ? (int)2 : (int)1);
				score[op] -= g[i][j];
				cl[i][j] = 0;
				if (op % 2 == res) return res;
			}
		}
		return op == 1 ? (int)0 : (int)1;
	};
	
	if (dfs(1)) cout << "Takahashi\n";
	else cout << "Aoki\n";
}

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

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

F - Subsequence LCM(数位dp)

应该算是数位dp吧,首先想到的肯定是选择的数一定是可以提供m的质因子的,但有个想遗漏的点是,如果m中有5个2,那一定要选择一个可以提供5个2的,多个数拼起来5个2是不可以的

所以先拆出来m中的所有质因子(需要质因子的种类和同种质因子乘起来的值),然后判断a中的每一个数可以给m提供多少价值,最后类似于背包dp

m如果为1的话要特判

实现细节还是蛮多的

#include <bits/stdc++.h>

using namespace std;

#define int long long
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 mod = 998244353;
const int maxn = 1e6 + 10;
const int mod1 = 954169327;
const int mod2 = 906097321;
const int INF = 0x3f3f3f3f3f3f3f3f;

void solve()
{
	int n, m;
	cin >> n >> m;
	vector<int> prime, val;
	int tmp = m;
	for (int i = 2; i * i <= m; i ++ )
	{
		if (tmp % i == 0)
		{
			prime.push_back(i);
			val.push_back(1);
			while (tmp % i == 0)
			{
				val[val.size() - 1] *= i;
				tmp /= i;
			}
		}
	}
	if (tmp != 1)
	{
		prime.push_back(tmp);
		val.push_back(tmp);
	}
	vector<int> cnt(1e5 + 10), dp(1e5 + 10);
	for (int i = 0; i < n; i ++ )
	{
		int x; cin >> x;
		int res = 0;
		for (int j = 0; j < prime.size(); j ++ )
		{
			if (x % val[j] == 0)
			{
				x /= val[j];
				if (x % prime[j] == 0) break;
				res |= (1 << j);
			}
			while (x % prime[j] == 0) x /= prime[j];
		}
		if (x == 1) cnt[res] ++ ;
	}
	vector<int> pw;
	pw.push_back(1);
	for (int i = 1; i <= n; i ++ ) pw.push_back(pw[pw.size() - 1] * 2 % mod);
	dp[0] = pw[cnt[0]];
	for (int i = 1; i < (1 << prime.size()); i ++ )
	{
		for (int j = ((1 << prime.size()) - 1); j >= 0; j -- )
		{
			dp[i | j] = (dp[i | j] + dp[j] * (pw[cnt[i]] - 1)) % mod;
		}
	}
	if (m == 1) dp[(1 << prime.size()) - 1] -- ;
	cout << dp[(1 << prime.size()) - 1] << '\n';
}

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

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

ATC - abc347

C - Ideal Holidays

每个值模上a+b,就能得出相对位置,然后排序,相邻的两个间距大于等于b,中间就可以塞下一组工作日,就输出Yes

#include <bits/stdc++.h>

using namespace std;

#define int long long
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 mod = 998244353;
const int maxn = 1e6 + 10;
const int mod1 = 954169327;
const int mod2 = 906097321;
const int INF = 0x3f3f3f3f3f3f3f3f;

void solve()
{
	int n, a, b;
	cin >> n >> a >> b;
	vector<int> d(n);
	for (int i = 0; i < n; i ++ )
	{
		cin >> d[i];
		d[i] %= (a + b);
	}
	sort(d.begin(), d.end());
	for (int i = 1; i < d.size(); i ++ )
	{
		if (d[i] - d[i - 1] - 1 >= b)
		{
			cout << "Yes\n";
			return;
		}
	}
	if (d[0] + a + b - d[d.size() - 1] - 1 >= b) cout << "Yes\n";
	else cout << "No\n";
	return;
}

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

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

D - Popcount and XOR(位运算)

这一题不难但是。。。以后一定不要写(1 << i),改成((i64)1 << i)算我求你了。。。

然后bitset是真的好用啊,查题解的时候看到了别人用

#include <bits/stdc++.h>

using namespace std;

#define int long long
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 mod = 998244353;
const int maxn = 1e6 + 10;
const int mod1 = 954169327;
const int mod2 = 906097321;
const int INF = 0x3f3f3f3f3f3f3f3f;

void solve()
{
	int a, b, c;
	cin >> a >> b >> c;
	int cnt = 0;
	for (int i = 0; i < 60; i ++ )
		if ((1 & (c >> i)) == 1) cnt ++ ;
	int sum = a + b;
	if (cnt > sum || (sum - cnt) % 2 != 0)
	{
		cout << "-1\n";
		return;
	}
	int suf = (sum - cnt) / 2;
	if (a < suf || b < suf)
	{
		cout << "-1\n";
		return;
	}
	int x = 0, y = 0;
	a -= suf, b -= suf;
	for (int i = 0; i < 60; i ++ )
	{
		if ((1 & (c >> i)) == 1)
		{
			if (a) x += ((i64)1 << i), a -- ;
			else if (b) y += ((i64)1 << i), b -- ;
			else
			{
				cout << "-1\n";
				return;
			}
		}
		else if (suf != 0)
		{
			x += ((i64)1 << i);
			y += ((i64)1 << i);
			suf -- ;
		}
		// cout << i << ' ' << x << ' ' << y << '\n';
	}
	if (suf != 0 || a != 0 || b != 0) cout << -1 << '\n';
	else cout << x << ' ' << y << '\n';
}

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

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

E - Set Add Query(前缀和)

记录下来每次加的值,求个前缀和

然后再根据每个数出现的区间为这一位加上相应的数

#include <bits/stdc++.h>

using namespace std;

#define int long long
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 mod = 998244353;
const int maxn = 1e6 + 10;
const int mod1 = 954169327;
const int mod2 = 906097321;
const int INF = 0x3f3f3f3f3f3f3f3f;

void solve()
{
	int n, m;
	cin >> n >> m;
	set<int> st;
	vector<int> a(m + 1), pre(m + 1);
	vector<vector<int>> op(n + 1);
	for (int i = 1; i <= m; i ++ )
	{
		int x; cin >> x;
		op[x].push_back(i);
		if (st.find(x) == st.end()) st.insert(x);
		else st.erase(x);
		a[i] = st.size();
	}
	for (int i = 1; i <= m; i ++ ) pre[i] = pre[i - 1] + a[i];
	pre.push_back(pre[pre.size() - 1]);

	for (int i = 1; i <= n; i ++ )
	{
		op[i].push_back(m + 1);
		int res = 0;
		for (int j = 1; j < op[i].size(); j += 2)
		{
			int p = op[i][j], q = op[i][j - 1];
			res += pre[p - 1] - pre[q - 1];
		}
		cout << res << ' ';
	}
}

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

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

F - Non-overlapping Squares(分类讨论+二维前缀和)

在正方形里面取三个小正方形只有这六种情况
在这里插入图片描述
dp[i][j][0/1/2/3] 分别表示以当前点为小正方形的右下角、左下角、右上角、左上角的和,六种情况分别算一下

#include <bits/stdc++.h>

using namespace std;

#define int long long
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 mod = 998244353;
const int maxn = 1e6 + 10;
const int mod1 = 954169327;
const int mod2 = 906097321;
const int INF = 0x3f3f3f3f3f3f3f3f;

void solve()
{
	int n, m;
	int ans = 0;
	cin >> n >> m;
	vector<vector<int>> a(n + 2, vector<int>(n + 2)), pre(n + 2, vector<int>(n + 2));
	vector<vector<vector<int>>> dp(n + 2, vector<vector<int>>(n + 2, vector<int>(4)));
	for (int i = 1; i <= n; i ++ )
		for (int j = 1; j <= n; j ++ )
			cin >> a[i][j];
	for (int i = 1; i <= n; i ++ )
		for (int j = 1; j <= n; j ++ )
			pre[i][j] = pre[i - 1][j] + pre[i][j - 1] - pre[i - 1][j - 1] + a[i][j];
	for (int i = n; i >= m; i -- )
		for (int j = n; j >= m; j -- )
			pre[i][j] = pre[i][j] - pre[i - m][j] - pre[i][j - m] + pre[i - m][j - m];
	for (int i = m; i <= n; i ++ )
		for (int j = m; j <= n; j ++ )
			dp[i][j][0] = max({pre[i][j], dp[i - 1][j][0], dp[i][j - 1][0]});
	for (int i = m; i <= n; i ++ )
		for (int j = n - m + 1; j > 0; j -- )
			dp[i][j][1] = max({pre[i][j + m - 1], dp[i - 1][j][1], dp[i][j + 1][1]});
	for (int i = n - m + 1; i > 0; i -- )
		for (int j = m; j <= n; j ++ )
			dp[i][j][2] = max({pre[i + m - 1][j], dp[i][j - 1][2], dp[i + 1][j][2]});
	for (int i = n - m + 1; i > 0; i -- )
		for (int j = n - m + 1; j > 0; j -- )
			dp[i][j][3] = max({pre[i + m - 1][j + m - 1], dp[i + 1][j][3], dp[i][j + 1][3]});
	for (int i = m; i <= n; i ++ )
		for (int j = m; j <= n; j ++ )
		{
			ans = max(ans, dp[n][j - m][0] + pre[i][j] + dp[1][j + 1][3]);
			ans = max(ans, dp[i - m][n][0] + pre[i][j] + dp[i + 1][1][3]);
			ans = max(ans, dp[n][j][0] + dp[i][j + 1][1] + dp[i + 1][j + 1][3]);
			ans = max(ans, dp[i][j][0] + dp[i + 1][j][2] + dp[1][j + 1][3]);
			ans = max(ans, dp[i][n][0] + dp[i + 1][j][2] + dp[i + 1][j + 1][3]);
			ans = max(ans, dp[i][j][0] + dp[i][j + 1][1] + dp[i + 1][1][3]);
		}
	cout << ans << '\n';
}

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

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

CF 1704D Magical Array(非常妙的前缀和)

题目链接

发现操作1对 ∑ i = 1 n a i × i \sum_{i=1}^{n}{a_i\times i} i=1nai×i 没有影响,操作2对它的影响是每次加1,所以只要求前面这个式子,找到值不一样的那个,再求差就可以了

学到了max_element函数,好用

想不到啊。。。

#include <bits/stdc++.h>

using namespace std;

#define int long long
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 mod = 998244353;
const int maxn = 1e6 + 10;
const int mod1 = 954169327;
const int mod2 = 906097321;
const int INF = 0x3f3f3f3f3f3f3f3f;

void solve()
{
	int n, m;
	cin >> n >> m;
	vector<int> sum(n);
	for (int i = 0; i < n; i ++ )
	{
		int res = 0;
		for (int j = 1; j <= m; j ++ )
		{
			int x; cin >> x;
			res += x * j;
		}
		sum[i] = res;
	}
	int idx = max_element(sum.begin(), sum.end()) - sum.begin();
	cout << idx + 1 << ' ' << sum[idx] - sum[min_element(sum.begin(), sum.end()) - sum.begin()] << '\n';
}

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

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

ATC - abc346

C - Σ

暴力

#include <bits/stdc++.h>

using namespace std;

#define int long long
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 mod = 998244353;
const int maxn = 1e6 + 10;
const int mod1 = 954169327;
const int mod2 = 906097321;
const int INF = 0x3f3f3f3f3f3f3f3f;

void solve()
{
	int n, k;
	cin >> n >> k;
	set<int> st;
	for (int i = 0; i < n; i ++ )
	{
		int x; cin >> x;
		st.insert(x);
	}
	int idx = 1, ans = 0;
	for (auto t : st)
	{
		while (t != idx)
		{
			ans += idx, idx ++ ;
			if (idx > k) break;
		}
		idx ++ ;
		if (idx > k) break;
	}
	if (idx < k) ans += (idx + k) * (k - idx + 1) / 2;
	cout << ans << '\n';
}

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

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

D - Gomamayo Sequence(前缀和)

这两天怎么一直在做前缀和啊好奇怪

因为最后的情况其实很固定,如果确定了哪两个相邻的数是一样的,整个字符串就已经固定了,所以先求出把原字符串变成“10101010…”的代价前缀和,再求出把原字符串变成“01010101^”的代价前缀和,然后枚举让哪两个位置一样,前一半用一个前缀和算代价,后一半用另一个前缀和算就可以

#include <bits/stdc++.h>

using namespace std;

#define int long long
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 mod = 998244353;
const int maxn = 1e6 + 10;
const int mod1 = 954169327;
const int mod2 = 906097321;
const int INF = 0x3f3f3f3f3f3f3f3f;

void solve()
{
	int n;
	string s;
	cin >> n >> s;
	vector<int> c(n);
	for (int i = 0; i < n; i ++ ) cin >> c[i];
	string s1 = "", s2 = "";
	for (int i = 0; i < n; i ++ )
	{
		if (i & 1)
		{
			s1.push_back('0');
			s2.push_back('1');
		}
		else 
		{
			s1.push_back('1');
			s2.push_back('0');
		}
	}
	vector<int> res1(n), res2(n);
	if (s[0] == '1') res2[0] = c[0];
	else res1[0] = c[0];
	for (int i = 1; i < n; i ++ )
	{
		res1[i] = res1[i - 1], res2[i] = res2[i - 1];
		if (s1[i] != s[i]) res1[i] += c[i];
		if (s2[i] != s[i]) res2[i] += c[i];
	}
	int ans = INF;
	for (int i = 1; i < n; i ++ )
	{
		// 换成1
		if (i & 1) ans = min(ans, res1[i - 1] + res2[n - 1] - res2[i - 1]);
		else ans = min(ans, res2[i - 1] + res1[n - 1] - res1[i - 1]);
		// 换成0
		if (i & 1) ans = min(ans, res2[i - 1] + res1[n - 1] - res1[i - 1]);
		else ans = min(ans, res1[i - 1] + res2[n - 1] - res2[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();
	}
}

E - Paint(逆向思考)

因为之后涂的颜色会对前面有影响,所以直接逆向思考,从后往前看,如果这个位置在后面涂过颜色了就直接忽略前面涂的颜色

#include <bits/stdc++.h>

using namespace std;

#define int long long
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 mod = 998244353;
const int maxn = 1e6 + 10;
const int mod1 = 954169327;
const int mod2 = 906097321;
const int INF = 0x3f3f3f3f3f3f3f3f;

void solve()
{
	int n, m, q;
	cin >> n >> m >> q;
	vector<bool> r(n + 1), c(m + 1);
	map<int, int> mp;
	int cnt1 = 0, cnt2 = 0;
	vector<array<int, 3>> a(q);
	for (int i = 0; i < q; i ++ ) cin >> a[i][0] >> a[i][1] >> a[i][2];
	for (int i = q - 1; i >= 0; i -- )
	{
		int op = a[i][0], x = a[i][1], cl = a[i][2];
		if (op == 1)
		{
			if (r[x]) continue;
			mp[cl] += m - cnt2;
			r[x] = true;
			cnt1 ++ ;
		}
		else
		{
			if (c[x]) continue;
			mp[cl] += n - cnt1;
			c[x] = true;
			cnt2 ++ ;
		}
	}
	int sum = 0;
	for (auto t : mp)
	{
		if (t.first == 0) continue;
		sum += t.second;
	}
	sum = n * m - sum;
	mp[0] = sum;
	vector<PII> ans;
	for (auto t : mp)
	{
		if (t.second > 0)
		{
			ans.push_back(t);
		}
	}
	cout << ans.size() << '\n';
	for (auto t : ans) cout << t.first << ' ' << t.second << '\n';
}

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

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

F - SSttrriinngg in StringString

本来的想法是先把确定的那个串拼好,但是发现实在是太长了根本不可能拼好,所以还是循环来看

很明显的二分,难点就是怎么去写这个check函数,从前往后看t串,t的每一位必须出现mid次才轮到下一位出现,小暴力循环s,实现起来还是很多细节的

#include <bits/stdc++.h>

using namespace std;

#define int long long
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 + 10;
const int mod = 998244353;
const int mod1 = 954169327;
const int mod2 = 906097321;
const int INF = 0x3f3f3f3f3f3f3f3f;

void solve()
{
	int n;
	string s, t;
	cin >> n >> s >> t;
	vector<vector<int>> pos(26);
	for (int i = 0; i < s.size(); i ++ ) pos[s[i] - 'a'].push_back(i);
	auto check = [&](int x)
	{
		if (x == 0) return true;
		int it = 0, sum = 0, cur = 0, left = x;
		while (sum <= n && cur < t.size())
		{
			int c = t[cur] - 'a';
			if (pos[c].size() == 0) return false;
			if (it == 0)
			{
				int cnt = pos[c].size();
				int cost = left / cnt;
				sum += cost;
				left -= cost * cnt;
				int md = left % cnt;
				if (md != 0)
				{
					sum ++ ;
					it = (pos[c][md - 1] + 1) % s.size();
					left -= md;
				}
				else
				{
					it = (pos[c].back() + 1) % s.size();
				}
			}
			else
			{
				int st = lower_bound(pos[c].begin(), pos[c].end(), it) - pos[c].begin();
				int cnt = pos[c].size() - st;
				if (left > cnt)
				{
					left -= cnt;
					it = 0;
				}
				else
				{
					it = (pos[c][st + left - 1] + 1) % s.size();
					left = 0;
				}
			}
			if (left == 0)
			{
				cur ++ ;
				left = x;
			}
		}
		return sum <= n;
	};
	int l = 0, r = 1e17;
	while (l < r)
	{
		int mid = l + r + 1 >> 1;
		if (check(mid)) l = mid;
		else r = mid - 1;
	}
	cout << r << '\n';
}

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

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

ATC - abc345

C - One Time Swap

简单的组合数学

#include <bits/stdc++.h>

using namespace std;

#define int long long
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 + 10;
const int mod = 998244353;
const int mod1 = 954169327;
const int mod2 = 906097321;
const int INF = 0x3f3f3f3f3f3f3f3f;

void solve()
{
	string s;
	cin >> s;
	map<int, int> mp;
	for (auto t : s) mp[t - 'a'] ++ ;
	int sum = 0, ans = 0;
	for (auto t : mp) sum += t.second;
	bool flag = false;
	for (auto t : mp)
	{
		if (t.second > 1) flag = true;
		ans += t.second * (sum - t.second);
	}
	ans /= 2;
	if (flag) ans ++ ;
	cout << ans << '\n';
}

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

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

D - Tiling

数据范围很小,爆搜一下,但是码力有点烂的我受不了了

#include <bits/stdc++.h>

using namespace std;

#define int long long
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 + 10;
const int mod = 998244353;
const int mod1 = 954169327;
const int mod2 = 906097321;
const int INF = 0x3f3f3f3f3f3f3f3f;

void solve()
{
	int n, h, w;
	cin >> n >> h >> w;
	vector<PII> a(n + 1);
	for (int i = 1; i <= n; i ++ ) cin >> a[i].first >> a[i].second;
	vector<vector<int>> st(h + 1, vector<int>(w + 1));
	vector<bool> used(n + 1);
	auto check = [&](int id)
	{
		for (int i = 1; i <= h; i ++ )
		{
			for (int j = 1; j <= w; j ++ )
			{
				if (st[i][j]) continue;
				if (i + a[id].first - 1 <= h && j + a[id].second - 1 <= w)
				{
					bool flag = true;
					for (int ii = i; ii < i + a[id].first; ii ++ )
					{
						for (int jj = j; jj < j + a[id].second; jj ++ )
						{
							if (st[ii][jj] > 0)
							{
								flag = false;
								break;
							}
						}
						if (!flag) break;
					}
					if (flag)
					{
						for (int ii = i; ii < i + a[id].first; ii ++ )
							for (int jj = j; jj < j + a[id].second; jj ++ )
								st[ii][jj] = id;
						return true;
					}
				}
			}
		}
		return false;
	};
	auto del = [&](int id)
	{
		for (int i = 1; i <= h; i ++ )
			for (int j = 1; j <= w; j ++ )
				if (st[i][j] == id) st[i][j] = 0;
	};
	function<bool(int)> dfs = [&](int sum)
	{
		if (sum == h * w) return true;
		for (int i = 1; i <= n; i ++ )
		{
			if (used[i]) continue;
			if (check(i))
			{
				used[i] = true;
				if (dfs(sum + a[i].first * a[i].second)) return true;
				used[i] = false;
				del(i);
			}
			swap(a[i].first, a[i].second);
			if (check(i))
			{
				used[i] = true;
				if (dfs(sum + a[i].first * a[i].second)) return true;
				used[i] = false;
				del(i);
			}
			swap(a[i].first, a[i].second);
		}
		return false;
	};
	if (dfs(0)) cout << "Yes\n";
	else cout << "No\n";
}

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

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

CF 1572A Book(拓扑排序)

题目链接

应该是一道很简单的拓扑排序,想的时候没有搞清楚前后结点的转换关系

#include <bits/stdc++.h>

using namespace std;

#define int long long
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 + 10;
const int mod = 998244353;
const int mod1 = 954169327;
const int mod2 = 906097321;
const int INF = 0x3f3f3f3f3f3f3f3f;

void solve()
{
	int n;
	cin >> n;
	vector<vector<int>> g(n + 1);
	vector<int> ind(n + 1), tm(n + 1);
	queue<int> q;
	int cnt = 0;
	for (int i = 1; i <= n; i ++ )
	{
		int k; cin >> k;
		for (int j = 0; j < k; j ++ )
		{
			int x; cin >> x;
			g[x].push_back(i);
		}
		ind[i] += k;
		if (k == 0)
		{
			q.push(i);
			tm[i] = 1;
			cnt ++ ;
		}
	}
	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 > t) tm[j] = max(tm[j], tm[t]);
			else tm[j] = max(tm[j], tm[t] + 1);
			ind[j] -- ;
			if (ind[j] == 0)
			{
				q.push(j);
				cnt ++ ;
			}
		}
	}
	if (cnt != n)
	{
		cout << "-1\n";
		return;
	}
	int ans = 0;
	for (int i = 1; i <= n; i ++ ) ans = max(ans, tm[i]);
	cout << ans << '\n';
}

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

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

CF 1036C Classy Numbers(枚举+二分)

题目链接

首先枚举出所有符合条件的数,然后二分查找

#include <bits/stdc++.h>

using namespace std;

#define int long long
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 + 10;
const int mod = 998244353;
const int mod1 = 954169327;
const int mod2 = 906097321;
const int INF = 0x3f3f3f3f3f3f3f3f;

vector<int> v;

void dfs(int cur, int cnt, int len)
{
	v.push_back(cur);
	if (len == 18) return;
	dfs(cur * 10, cnt, len + 1);
	if (cnt < 3)
	{
		for (int i = 1; i <= 9; i ++ )
		{
			dfs(cur * 10 + i, cnt + 1, len + 1);
		}
	}
}

void pre()
{
	for (int i = 1; i <= 9; i ++ ) dfs(i, 1, 1);
	v.push_back(1e18);
	sort(v.begin(), v.end());
}

void solve()
{
	int l, r;
	cin >> l >> r;
	int ll = lower_bound(v.begin(), v.end(), l) - v.begin();
	int rr = upper_bound(v.begin(), v.end(), r) - v.begin();
	cout << rr - ll << '\n';
}

signed main()
{
	ios::sync_with_stdio(false);
	cin.tie(0), cout.tie(0);
	pre();
	int t = 1;
	cin >> t;
	while (t--)
	{
		solve();
	}
}

CF 1554C Mikasa(位运算)

题目链接

一开始想着二分但是这个范围也太大了,二分肯定会爆

查了题解,首先把 n ^ m = x 换成 n ^ x = m (交换律)

所以我们要找的就是满足 n ^ x >= (m + 1) 最小的 x

从高位到低位一位一位看,如果当前位:

  • n0m+10 ,那么 x0
  • n0m+11 ,那么 x1
  • n1m+10 ,那么 x0,且直接跳出
  • n1m+11 ,那么 x0
#include <bits/stdc++.h>

using namespace std;

#define int long long
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 + 10;
const int mod = 998244353;
const int mod1 = 954169327;
const int mod2 = 906097321;
const int INF = 0x3f3f3f3f3f3f3f3f;

void solve()
{
	int n, m;
	cin >> n >> m;
	int ans = 0;
	for (int i = 32; i >= 0; i -- )
	{
		if (!((n >> i) & 1) && !(((m + 1) >> i) & 1)) continue;
		else if (((n >> i) & 1) && !(((m + 1) >> i) & 1)) break;
		else if (!((n >> i) & 1) && (((m + 1) >> i) & 1)) ans += (1 << i);
	}
	cout << ans << '\n';
}

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

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

CF 1327E Count The Blocks(计数)

题目链接

计数题又没有做出来 唉

首先要去想怎么构造字符串能对长度为 i 的答案有1的贡献,很容易想到这个长度为 i 的部分有三种可能:

  • 在整个长度为 n 的字符串的最左边
  • 在整个长度为 n 的字符串的最右边
  • 在整个长度为 n 的字符串的中间

第一种和第二种情况,只要确保和长度为 i 的部分相邻的那一个元素与长度为 i 的部分取值不同即可

第三种情况,需要确保和长度为 i 的部分相邻的两个元素与长度为 i 的部分取值不同

#include <bits/stdc++.h>

using namespace std;

#define int long long
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 + 10;
const int mod = 998244353;
const int mod1 = 954169327;
const int mod2 = 906097321;
const int INF = 0x3f3f3f3f3f3f3f3f;

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

void solve()
{
	int n;
	cin >> n;
	vector<int> dp(n + 1);
	dp[n] = 10, dp[n - 1] = 180;
	for (int i = n - 2; i >= 1; i -- )
	{
		dp[i] = (10 * 9 * qpow(10, n - i - 1, mod) % mod * 2 % mod + 10 * 9 * 9 * qpow(10, n - i - 2, mod) % mod * (n - i - 1) % mod) % mod;
	}
	for (int i = 1; i <= n; i ++ ) cout << dp[i] << ' ';
	cout << '\n';
}

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

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

CF 1381B Unmerge(背包dp)

题目链接

跑了一发剪枝的dfs爆了,果然cf没有暴力题

然后很容易发现,一个数与这个数之后出现的第一个比它大的数,中间的所有数都应该和这个数在同一个数组,并且排在这个数后面

根据这个,可以将原数组分成很多个小段,然后类似背包去做就可以了

#include <bits/stdc++.h>

using namespace std;

#define int long long
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 + 10;
const int mod = 998244353;
const int mod1 = 954169327;
const int mod2 = 906097321;
const int INF = 0x3f3f3f3f3f3f3f3f;

void solve()
{
	int n;
	cin >> n;
	vector<int> a;
	int maxx = 0;
	for (int i = 1; i <= 2 * n; i ++ ) {
		int x; cin >> x;
		if (x < maxx) a[a.size() - 1] ++ ;
		else {
			a.push_back(1);
			maxx = x;
		}
	}
	sort(a.begin(), a.end());
	vector<bool> f(n + 1);
	f[0] = true;
	for (int i = 0; i < a.size(); i ++ )
	{
		for (int j = n; j >= a[i]; j -- )
		{
			if (!f[j] && f[j - a[i]]) f[j] = true;
		}
	}
	cout << (f[n] ? "YES\n" : "NO\n");
}

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

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

ATC abc351E Jump Distance Sum

题目链接

因为坐标系斜着计算困难,所以把移动步数全部换成水平or垂直的

也就是将坐标系旋转45度,并把坐标变为原来的 2 \sqrt{2} 2

原来的 ( x ,   y ) (x,\ y) (x, y) 全部变成了 ( x + y ,   x − y ) (x+y,\ x-y) (x+y, xy)

移动规则变成了可以向上下左右移动 2 个单位长度,也就是坐标奇偶性相同的才能互相达到

之后计算曼哈顿距离即可

注意因为我们将坐标轴变成 2 \sqrt{2} 2 倍了,所以最后答案要除以 2

#include <bits/stdc++.h>

using namespace std;

#define int long long
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 = 10;
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> v[4];
	for (int i = 0; i < n; i ++ )
	{
		int x, y;
		cin >> x >> y;
		if ((x + y) % 2 == 0)
		{
			v[0].push_back(x + y);
			v[1].push_back(x - y);
		}
		else
		{
			v[2].push_back(x + y);
			v[3].push_back(x - y);
		}
	}
	for (int i = 0; i < 4; i ++ ) sort(v[i].begin(), v[i].end());
	int ans = 0;
	for (int i = 0; i < 4; i ++ )
	{
		int tmp = 0;
		for (int j = 1; j < v[i].size(); j ++ ) tmp += v[i][j] - v[i][0];
		for (int j = 1; j < v[i].size(); j ++ ) ans += tmp, tmp -= (v[i].size() - j) * (v[i][j] - v[i][j - 1]);
	}
	cout << ans / 2 << '\n';
}

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

	int t = 1;
	// cin >> t;
	while (t--)
	{
		solve();
	}
}
  • 12
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Texcavator

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

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

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

打赏作者

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

抵扣说明:

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

余额充值