codeforces 构造题专题(easy version)
1.CF1768C Elemental Decompress(*1300 贪心、构造)
参考@此处
用表示仍未填入中的数字。
贪心策略:
将未重复的数尽量填入中,重复的数填入中,同时更新。
对于中每一位未填的数,贪心选择中最大的数且该数;的处理相同。
参考做法的代码相当优美,学到很多。
#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
#define cerr(x) std::cerr << (#x) << " is " << (x) << '\n'
#define IOS std::ios::sync_with_stdio(false);std::cin.tie(nullptr);
#define PII pair<int, int>
#define pdd pair<double,double>
#define PLL pair<LL,LL>
#define LL long long
const double CLOCKS_PER_SECOND = ((clock_t) 1000);
const double CLOCKS_PER_MILLISECOND = ((clock_t) 1);
const int N = 2e5 + 10, M = 1e8, mod = 1e9 + 7, inf = 0x3f3f3f3f;
const double eps = 1e-6;
//#define x first
//#define y second
int T;
bool cmp(PII &a, PII &b) {
return a.second < b.second;
}
bool cmp2(PII &a, PII &b) {
return a.first < b.first;
}
void solve() {
int n, Max = -1;
cin >> n;
vector<int> a(n);
set<int> s1, s2;
for (auto &ai: a) cin >> ai, Max = max(Max, ai);
if (Max < n) {
cout << "NO" << endl;
return;
}
vector<int> p(n), q(n);
for (int i = 1; i <= n; i++) s1.insert(i), s2.insert(i);
for (int i = 0; i < n; i++) {
if (s1.count(a[i])) s1.erase(p[i] = a[i]);
else if (s2.count(a[i])) s2.erase(q[i] = a[i]);
else {
cout << "NO" << endl;
return;
}
}
for (int i = 0; i < n; i++) {
if (!p[i]) {
auto it = s1.lower_bound(q[i]);
if (it != s1.end() && *it == q[i]) s1.erase(p[i] = *it);//找到了,而且值=q[i]
else if (it == s1.begin()) {
cout << "NO" << endl;
return;
} else {
it = prev(it);
s1.erase(p[i] = *it);
}
} else {
auto it = s2.lower_bound(p[i]);
if (it != s2.end() && *it == p[i]) s2.erase(q[i] = *it);
else if (it == s2.begin()) {
cout << "NO" << endl;
return;
} else {
it = prev(it);
s2.erase(q[i] = *it);
}
}
}
cout << "YES" << endl;
for (int i = 0; i < n; i++) cout << p[i] << " \n"[i == n - 1];
for (int i = 0; i < n; i++) cout << q[i] << " \n"[i == n - 1];
return;
}
signed main() {
IOS;
cin >> T;
while (T--)
solve();
}
2A.Make Nonzero Sum (easy version) (*1300 贪心、构造)
因为不要求最小区间数,所以可以一个个拆开看。我们发现,,所以一个大区间一定能够拆分成或的区间。故如果为奇数是无解的。
讨论:如果两个数不相同,那么不为,故我们贪心的将其分为,这样两者和为如果相同,则直接计入一个区间。
#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
#define cerr(x) std::cerr << (#x) << " is " << (x) << '\n'
#define IOS std::ios::sync_with_stdio(false);std::cin.tie(nullptr);
#define PII pair<int, int>
#define pdd pair<double,double>
#define PLL pair<LL,LL>
#define LL long long
const double CLOCKS_PER_SECOND = ((clock_t) 1000);
const double CLOCKS_PER_MILLISECOND = ((clock_t) 1);
const int N = 2e5 + 10, M = 1e8, mod = 1e9 + 7, inf = 0x3f3f3f3f;
const double eps = 1e-6;
//#define x first
//#define y second
int T;
int a[N];
void solve() {
int n;
cin >> n;
vector<PII > v;
int sum = 0;
for (int i = 1; i <= n; i++)
cin >> a[i], sum += a[i];
if (n & 1) {
cout << -1 << endl;
return;
}
for (int i = 1; i <= n; i += 2) {
if (a[i] == a[i + 1]) v.push_back({i, i + 1});
else v.push_back({i, i}), v.push_back({i + 1, i + 1});
}
cout << v.size() << endl;
for (auto &i: v) cout << i.first << " " << i.second << endl;
return;
}
signed main() {
IOS;
cin >> T;
while (T--)
solve();
}
2B.Make Nonzero Sum (hard version)(*1500 贪心、构造)
首先,可以判断出:若非的个数为奇数时无解,原因与相同。
的情况不用再重复,我们判断如下情况:
-
:可以拆分成
-
:可以拆分成
前置全部单独划分为一个区间。
#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
#define cerr(x) std::cerr << (#x) << " is " << (x) << '\n'
#define IOS std::ios::sync_with_stdio(false);std::cin.tie(nullptr);
#define PII pair<int, int>
#define pdd pair<double,double>
#define PLL pair<LL,LL>
#define LL long long
const double CLOCKS_PER_SECOND = ((clock_t) 1000);
const double CLOCKS_PER_MILLISECOND = ((clock_t) 1);
const int N = 2e5 + 10, M = 1e8, mod = 1e9 + 7, inf = 0x3f3f3f3f;
const double eps = 1e-6;
//#define x first
//#define y second
int T;
int a[N];
void solve() {
int n;
cin >> n;
vector<PII > v;
int sum = 0;
for (int i = 1; i <= n; i++)
cin >> a[i], sum += (a[i] != 0);
if (sum & 1) {
cout << -1 << endl;
return;
}
for (int i = 1; i <= n;) {
while (!a[i] && i <= n) {
v.push_back({i, i});
i++;
}
if (i > n) break;
int l = i, r = i + 1;
if (a[r]) {
if (a[l] == a[r]) v.push_back({l, l + 1});
else {
v.push_back({l, l});
v.push_back({l + 1, l + 1});
}
} else {
v.push_back({l, l});
while (!a[r] && r <= n) {
v.push_back({r, r});
r++;
}
if (a[l] != a[r]) v.push_back({r, r});
else v.back().second = r;//更改为{0,1},凑成(1)+(0-1)
}//{1,1},{0,0},1
i = r + 1;
}
cout << v.size() << endl;
for (auto &i: v) cout << i.first << " " << i.second << endl;
return;
}
signed main() {
IOS;
cin >> T;
while (T--)
solve();
}
3.Vlad and a Pair of Numbers(*1400 位运算,构造)
由常见的推论得:
故化简得:
分析的取值:
-
的第位为,第位为,不成立
-
的第位为,第位为,成立,此时与第位不相同即满足;
-
的第位为,第位为,成立,此时与第位均为时满足;
-
的第位为,第位为,成立,此时与第位均为时满足;
分析可知,无解的情况当且仅当有连续两位为。故对于可行解一定是满足排列的。
不妨如下构造:
若。
#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
#define cerr(x) std::cerr << (#x) << " is " << (x) << '\n'
#define IOS std::ios::sync_with_stdio(false);std::cin.tie(nullptr);
#define PII pair<int, int>
#define pdd pair<double,double>
#define PLL pair<LL,LL>
#define rep(i, j, k) for(int i=j;i<=k;i++)
#define int long long
const double CLOCKS_PER_SECOND = ((clock_t) 1000);
const double CLOCKS_PER_MILLISECOND = ((clock_t) 1);
const int N = 1e6 + 10, M = 1e8, mod = 1e9 + 7, inf = 0x3f3f3f3f;
const double eps = 1e-6;
//const int fac[] = {1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880};
const int dx[] = {-1, 0, 0, 1}, dy[] = {0, 1, -1, 0};
//#define x first
//#define y second
//int fac[N];
int qpow(int a, int b) {
int ans = 1LL, base = a;
while (b) {
if (b & 1) ans = (ans * base) % mod;
base = (base * base) % mod;
b >>= 1;
}
return ans;
}
/*
int C(int n, int k) {
if (k > n) return 0;
return (fac[n] * qpow(fac[k], mod - 2) % mod) * qpow(fac[n - k], mod - 2) % mod;
}
int Lucas(int n, int k) {
if (!k) return 1LL;
return C(n % mod, k % mod) * Lucas(n / mod, k / mod) % mod;
}
*/
int T;
int fac[32 + 5];
void solve() {
int n;
cin >> n;
vector<int> v(32 + 5), a(35, 0), b(35, 0);
if (n & 1) {
cout << -1 << endl;
return;
}
int t = n, tot = 0;
while (t) {
v[tot++] = t % 2, t /= 2;
}
for (int i = 0; i < tot - 1; i++) {
if (v[i] & v[i + 1]) {
cout << -1 << endl;
return;
}
}
for (int i = 0; i < tot; i++) {
if (v[i]) {//(n)2=1 0
a[i] = 1, b[i] = 0;
a[i - 1] = b[i - 1] = 1;
}
}
int numa = 0, numb = 0;
for (int i = 0; i < tot; i++) {
if (a[i]) numa += fac[i];
if (b[i]) numb += fac[i];
}
if ((numa ^ numb) != ((numa & numb) << 1)) {
cout << -1 << endl;
return;
}
cout << numa << " " << numb << endl;
}
signed main() {
IOS;
for (int i = 0, num = 1; i < 32 + 5; i++, num *= 2) fac[i] = num;
cin >> T;
while (T--)
solve();
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!