首页 > 其他分享 >YC312A [ 20240702 CQYC省选模拟赛 T1 ] 第一题(diyiti)

YC312A [ 20240702 CQYC省选模拟赛 T1 ] 第一题(diyiti)

时间:2024-07-10 22:08:26浏览次数:19  
标签:YC312A now 20240702 省选 res int 子集 isl include

题意

给定一个长度为 \(n\) 的可重集,以及正整数 \(k\)。

设一个子集的价值为子集中最大值减去最小值,你需要将这个可重集划分为 \(k\) 个子集,使得价值之和最小,子集需要满足不重。

\(n, k \le 100\)。

Sol

思考一下发现如果不记录每个子集的信息是不好做的。

考虑将所有子集的大小记录下来,发现这个的数量是 \((0, 0)\) 走到 \((k, n / k)\) 的方案数,显然为 \(C(n / k + k, n / k)\)。当 \(k\) 取 \(\sqrt n\) 时有最大值 \(C(2 \sqrt n, \sqrt n)\)。

简单跑一下发现这个东西只有 \(1.8 \times 10 ^ 5\)。

上个暴力 \(\text{dp}\),设 \(f_{i, j, S}\) 表示前 \(i\) 小个数,第 \(i\) 个数放在大小为 \(j\) 的集合之中,每个子集的大小集合为 \(S\)。

转移显然,若 \(s_i = s_{i = 1}\) 保证当前转移的 \(j \le j'\) 即可,因为之前放的相同的元素的集合一定是 \(\ge j + 1\) 的。

时间复杂度 \(O(nk\timesC(2 \sqrt n, \sqrt n))\),具体实现中可能需要使用 \(\text{map}\) 放 \(\text{vector}\) 的编号,这样会挂 \(\log\),可能过不去。

可以考虑交换一下枚举顺序,把保存上一个状态的 \(\text{vector}\) 拆开,合并处理 相同的 \(S\),这样 \(\log\) 就在外面了。

Code

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <map>
#include <array>
#include <vector>
#define int long long
#define pii pair <int, int>
using namespace std;
#ifdef ONLINE_JUDGE

#define getchar() (p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 1 << 21, stdin), p1 == p2) ? EOF : *p1++)
char buf[1 << 23], *p1 = buf, *p2 = buf, ubuf[1 << 23], *u = ubuf;

#endif
int read() {
	int p = 0, flg = 1;
	char c = getchar();
	while (c < '0' || c > '9') {
		if (c == '-') flg = -1;
		c = getchar();
	}
	while (c >= '0' && c <= '9') {
		p = p * 10 + c - '0';
		c = getchar();
	}
	return p * flg;
}
void write(int x) {
	if (x < 0) {
		x = -x;
		putchar('-');
	}
	if (x > 9) {
		write(x / 10);
	}
	putchar(x % 10 + '0');
}
bool _stmer;

#define fi first
#define se second

const int N = 2e5 + 5, M = 105, inf = 1e12;

map <vector <int>, int> mp;
array <vector <int>, N> idx;
vector <int> isl;

int cnt = 0, tot = 0;

void dfs(int step, int n, int k) {
	tot++;
	if (step == k) {
		cnt++;
		mp[isl] = cnt, idx[cnt] = isl;
		return;
	}
	int st = isl.size() ? isl.back() : 0;
	for (int i = st; i <= n / k; i++)
		isl.push_back(i), dfs(step + 1, n, k), isl.pop_back();
}

array <array <array <int, N>, M>, 2> f;
array <int, M> s;

bool _edmer;
signed main() {
	cerr << (&_stmer - &_edmer) / 1024.0 / 1024.0 << "MB\n";
	int n = read(), k = read();
	vector <int> tp;
	for (int i = 1; i <= n; i++) s[i] = read(), tp.push_back(s[i]);
	sort(s.begin() + 1, s.begin() + 1 + n);
	sort(tp.begin(), tp.end()), tp.erase(unique(tp.begin(), tp.end()), tp.end());
	dfs(0, n, k);
	int pl = 1;
	map <int, vector <int> > q, _q;
	q[1].push_back(0);
	for (int i = 0; i < M; i++)
		f[0][i].fill(inf), f[1][i].fill(inf);
	f[0][0][1] = 0;
	for (int i = 1; i <= n; i++) {
		for (auto S : q) {
			vector <int> res = idx[S.fi];
			for (int j = 1; j <= k; j++) {
				for (auto p : S.se) {
					if (s[i] == s[i - 1] && res[j - 1] > p)
						continue;
					if (j < k && res[j - 1] == res[j]) continue;
					if (res[j - 1] == n / k) continue;
					res[j - 1]++;
					int now = 0, jl = res[j - 1] - 1;
					if (res[j - 1] == 1) now += -s[i];
					if (res[j - 1] == n / k) now += s[i];
					if (f[pl][jl][mp[res]] >
						f[pl ^ 1][p][S.fi] + now) {
						_q[mp[res]].push_back(jl);
						f[pl][jl][mp[res]] =
							f[pl ^ 1][p][S.fi] + now;
					}
					res[j - 1]--;
				}
			}
		}
		pl ^= 1, q = _q, _q.clear();
	}
	int ans = inf;
	for (int i = 0; i <= n / k; i++)
		ans = min(ans, f[pl ^ 1][i][cnt]);
	if (ans == inf)
		puts("-1");
	else write(ans), puts("");
	return 0;
}

标签:YC312A,now,20240702,省选,res,int,子集,isl,include
From: https://www.cnblogs.com/cxqghzj/p/18295113

相关文章

  • YC311A [ 20240701 CQYC省选模拟赛 T1 ] 好串(good)
    题意给定一个长度为\(n\)的\(01\)串。定义一个串是好的当且仅当该串的所有前缀以及所有后缀的\(1\)的数量大于等于\(0\)的数量。你需要维护\(q\)个查询,每次求\(S_{l,...,r}\)的子串最少添加的\(1\)的个数使得该子串是好的。Sol首先不难发现一个正确的贪心,也......
  • YC314A [ 20240704 CQYC省选模拟赛 T1 ] 士兵(solider)
    题意给定一张\(n\)个点\(m\)条边的有向图,每条边上有一个字母。\(q\)次询问,每次询问\(s\tot\)中的最短回文路径的长度是多少。\(n\le10^3,m\le10^5\)Sol区间\(\text{dp}\),设\(f_{i,j}\)表示从\(i\)到\(j\)的最短回文路径的长度。每次枚举一条边\(......
  • P10218 [省选联考 2024] 魔法手杖 题解
    题目描述:给定序列\(a_1,\cdots,a_n\)和\(b_1,\cdots,b_n\),满足\(a_i\in[0,2^k-1],b_i\ge0\),你需要给出\(S\subseteq\{1,\cdots,n\}\)和\(x\in[0,2^k-1]\)满足:\(\sum\limits_{i\inS}b_i\lem\)。最大化\(val(S,x)=\min\big(\min\limits_{i\inS......
  • YC309A [ 20240627 CQYC省选模拟赛 T1 ] 或(or)
    题意给定一个可重集\(S\),求所有的前缀的集合的代价。定义一个集合的代价为:\[\max_x\left((\max_ib_i\lvertx)-(\min_ib_i\lvertx)\right)\]\(n\le10^6,V\le2\times10^6\)Sol首先看到这个式子直接开划。称较大的数为\(b_i\),较小的数为\(b_j\)。直......
  • YC307B [ 20240625 CQYC省选模拟赛 T2 ] 一个题(ynoi)
    题意你需要维护一个可重集\(S\),支持插入删除以及查询最大的方案使得给定正整数\(k\),划分为\(k\)个非空子集的按位与结果之和最大。\(n\le10^5\)Sol先上个trie。然后考虑一次查询怎么搞。先转化一下,如果需要划分为\(k\)个子集,显然需要合并\(n-k\)次。我们只......
  • 联合省选 2024 游记
    省流:abs(__int128)纯属去体验一下。FJ-S0124,谁都比不上我八倍队线。Day1上场。看T1。这个题目背景咋和题目一点关系都没有。。。盯了一会儿发现可以把\(x,y\)加起来判断就可以了。然后花十分钟码了一个直接枚举答案的,发现答案可能很大,于是开始拆贡献。这里其实已经有想过......
  • Luogu P9542 [湖北省选模拟 2023] 棋圣 alphago
    2023.08.19:修改了一处笔误。手玩发现对于一颗生成树,如果存在至少一个点的度数\(>2\)(即不为链),那么肯定能使得所有棋子都在一条边的两个端点上。因为有度数\(>2\)的点的存在,这里就可以合并与其相连的点的棋子。先考虑非链的情况的答案,记两部分棋子黑白棋子颜色分别为\(c(a/......
  • YC307A [ 20240622 CQYC省选模拟赛 T1 ] 划船(boat)
    题意给定一个有向图\(G\),以及将所有边反向重连的无向图\(T\)。你最多可以在\(T\)上连续走\(k\)条边,走过每条边的代价都为\(1\),然后必须在\(G\)的对应点上走一条边以恢复体力。若当前对应点没有出边,则停留在该点\(1\)代价。求每个点到\(n\)的最小代价。Sol考......
  • 省选训练总结
    目录2024.2.19T1题目大意solutionT2题目大意solution2024.2.20T1T22023.2.22T1题目大意solution2023.2.23T1题目大意solutionT2题目大意solution2024.2.26T1题目大意solutionT2题目大意solutionT3题目大意solution2024.2.27T1题目大意solutionT3题目大意solution2024.2.28补题2024......
  • YC303C [ 20240617 CQYC省选模拟赛 T3 ] Generals(generals)
    题意给定一张\(n\timesm\)的地图。对于第\(0\)列,第\(m+1\)列,第\(0\)行,第\(n+1\)行,有\(2n+2m\)个人,每个人面朝地图中心。每个人走到别人染过色的位置,或走出地图,将走过的地方染色。你需要求出共有多少种本质不同的染色方案。\(n,m\le10^6\)Sol直接......