E. Increasing Subsequences

发布时间:2024年01月23日

?Part1? ? 寒假思维训练之每日一道构造题(思维 + 构造 + 数学)题目链接: Problem - E - Codeforces

题意:
给定一个整数n,数字n的范围是[2, 1e18],闭区间,要求构造一个递增子序列(可以不连续)的数量为n的序列,空序列也算是递增子序列,构造一个长度<= 200的序列满足这个性质,序列元素abs(a[i]) <= 1e9


Part2? 题解(数学证明):

题解(数学证明):

求解偶数的情况,当n % 2, 先求n - 1,这样子保证了二进制不包含{2^{^{0}}}位:?

1、已知n,有:n = \sum_{} {2^{^{i}}},设?i \epsilon \begin{Bmatrix} i1, i2, i3, i4,i5,...,ik& \end{Bmatrix},i是n的每一个二进制位。
2、设?j = max(\begin{Bmatrix} i1, i2, i3, i4,i5,...,ik& \end{Bmatrix}),记录Ans为上升序列的数量

3、我们观察一下构造一个递增块(后面简称为块)有什么性质,当我们只构造一个块时,定它的长度为x的时候,它恰好有2^{^{x}}个递增序列,那我们必然可以这样构造:先构造一个块有j = max(\begin{Bmatrix} i1, i2, i3, i4,i5,...,ik& \end{Bmatrix})个元素,此时Ans = {2^{^{j}}}这个地方要注意了,此时的Ans是包含了将序列删除成空序列的方案,所以后面统一不需要考虑删除成空。设该块元素序列为:{a[1], a[2], a[3], ... ,a[j]}, a[1] > -1e9, a[i] < a[i + 1], i \varepsilon [1,j],往后加块时,从二进制位大的位置往小的位置枚举,当枚举到二进制位u时,必然满足u < j,此时取第一个块的第u + 1个元素a[u + 1],此时Ans = {2^{^{j}}} + {2^{^{u}}},接下来是说明一下为什么:

符号说明:a[i....j] (i <= j) <=> a[i], a[i + 1], ..., a[j]nextu:?u的下一个二进制位

\because a[1...u] < a[u + 1] < a[j] \\,此时统计带有a[u +1]的递增子序列,那么必然是删除a[u + 1 ... j]部分,剩下的a[1... u]部分可删可不删,并且a[u + 1]不能删除,所以就是{2^{^{u}}}

\because a[u + 1] > a[nextu + 1] \\?,所以显然后面的直接累加上来最终得到了n。
4、最初的n如果是奇数,就在后面加上一个-1e9,因为不用考虑删除成空,它必然小于前面的所有数字,所以贡献值就是1。

5、证毕。


Part3:? ?代码部分(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;
}

?

文章来源:https://blog.csdn.net/m0_74847145/article/details/135762379
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。