适合喜欢算法、对算法感兴趣的朋友。
今天又来更新啦,断更一天,有点摆了,今天继续补上,献上一道1800的构造。
摘要:
part1:关于一些构造题的总结
part2: 每日一题: Problem - E - Codeforces (链接在此处,有需自取)
part3: 数学证明、题解 (尽量保证严谨、详细)
part4: 代码(cpp版本,后续可能会更新python版本)
Part1 先给大家分享一下我总结归纳的一些构造题模型,一点自己的浅薄之见:
1、前后缀贪心,比如说观察前后缀的sum,去看以后怎么考虑最好。Problem - 1903C - Codeforces
2、双指针贪心法,考虑两端相消或者相互作用,还有就是考虑左右边界。 Problem - 1891C - Codeforces
Problem - 1907D - Codeforces
3、转换观察法,有些关系可以抽象成图,观察图的某些性质去总结规律。也可以抽象成一个集合,两个集合相等可以说明有解可构造。Problem - 1891C - Codeforces
4、打表找规律,一般没什么规律可循即可打表找规律,一般和数论有关的很喜欢考,acm也喜欢考,属于人类智慧题。Problem - 1916D - Codeforces
5、公式推导演算,常见的分为公式的等价变形、公式的化简(这个常考,一般需要先证明某些性质,可以直接抵消,一般如果原公式处理起来很复杂时就可以考虑)。Problem - 1889B - Codeforces
6、考虑奇偶数去简化问题或者分类问题,从其中的一些运算性质入手,因为奇数偶数的加减以及%运算(这个结论很重要)的结果的奇偶性是固定的,Problem - 1898C - Codeforces
7、根据性质构造模型,看看能不能分成几个块,几个不同的集合,再选择算法去解决。Problem - 1873G - Codeforces
8、考虑从小到大处理,或者是从大到小处理,有时候先处理小的对大的不会有影响,或者反过来,这样的处理顺序是最完美的。Problem - 1904D2 - Codeforces
9、边界贪心法,一般要在问题的最边界处考虑,有时候这样做结果是最优的,或者考虑边界上的影响,假如让影响最小,就使得影响<= 固定值 。 Problem - E - Codeforces and Problem - 1903C - Codeforces
Part2 寒假思维训练之每日一道构造题(思维 + 构造 + 数学)题目链接: Problem - E - Codeforces
题意:
给定一个整数,数字n的范围是,闭区间,要求构造一个递增子序列(可以不连续)的数量为的序列,空序列也算是递增子序列,构造一个长度的序列满足这个性质,序列元素
Part3 题解(数学证明):
题解(数学证明):
求解偶数的情况,当n % 2, 先求n - 1,这样子保证了二进制不包含位:
1、已知n,有:,设 ,i是n的每一个二进制位。
2、设 ,记录为上升序列的数量3、我们观察一下构造一个递增块(后面简称为块)有什么性质,当我们只构造一个块时,定它的长度为的时候,它恰好有个递增序列,那我们必然可以这样构造:先构造一个块有个元素,此时,这个地方要注意了,此时的是包含了将序列删除成空序列的方案,所以后面统一不需要考虑删除成空。设该块元素序列为:,往后加块时,从二进制位大的位置往小的位置枚举,当枚举到二进制位时,必然满足,此时取第一个块的第个元素,此时,接下来是说明一下为什么:
符号说明:, u的下一个二进制位
,此时统计带有的递增子序列,那么必然是删除部分,剩下的部分可删可不删,并且不能删除,所以就是。
,所以显然后面的直接累加上来最终得到了n。
4、最初的n如果是奇数,就在后面加上一个,因为不用考虑删除成空,它必然小于前面的所有数字,所以贡献值就是1。5、证毕。
Part4: 代码部分(cpp版本):
#include <bits/stdc++.h> #define int long long #define ff first #define ss second using namespace std; using PII = pair<int, int>; constexpr int N = 1e5 + 10; constexpr int inf = 0x3f3f3f3f; int n, m; void solve() { cin >> n; m = n; if(n % 2) -- m; vector<int> ans; int idx = -1; for(int i = 62; i >= 1; i -- ) if(m >> i & 1) { int u = 1e9 - 200; for(int j = 0; j < i; j ++ ) ans.push_back(u ++); idx = i; break; } vector<int> us; for(int i = idx - 1; i >= 1 && i != -1; i -- ) if(m >> i & 1) us.push_back(ans[i]); if(n % 2) us.push_back(-1e9); if(ans.size() + us.size() <= 200) { cout << ans.size() + us.size() << endl; for(auto t : ans) cout << t << ' '; for(auto t : us) cout << t << ' '; cout << endl; } else cout << -1 << endl; } signed main() { int ts; cin >> ts; while(ts --) solve(); return 0; }