构造题合集

简介

构造题是一种有趣的题目类型,一般会给定几个条件,要求构造出符合这些条件的数字/序列等,与数学关联较大

题目

CF1603B.Moderate Modular Mode

题目链接CF1603B

题意

给定 2 个偶数 x,y ,找到一个整数 n 满足 nmodx=ymodn

分析

我们从 x,y 的大小关系分类考虑。若 x=y ,显然可以取 n=x 。若 x>y ,可以取 n=x+y ,此时 (x+y)modx=ymod(x+y)=y 。若 x<y ,发现此时难以找到一个符合条件的 n ,可以借助图像:

p=kx(k+1)x>y ,那么 p=yymodx ,如果取 py 的中点为 n ,可以得出 nmodx=|PN|,ymodn=|NY| ,满足 nmodx=ymodn ,所以 n=y12(ymodx)

#include<bits/stdc++.h>
using namespace std;

int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);
    int t;
    cin >> t;
    while(t--) {
        int x, y;
        cin >> x >> y;
        if(x > y)
            cout << x + y << endl;
        else if(x == y)
            cout << x << endl;
        else
            cout << y - (y % x) / 2 << endl;
    }
    return 0;
}

CF1608B.Build the Permutation

题目链接CF1608B

题意

给定 3 个整数 n,a,b 判断是否存在满足以下条件的 1n 的排列:

  • 有且仅有 a 个在区间 [2,n1] 内的整数 i 满足 pi1<pi,pi>pi+1 (local maximum)
  • 有且仅有 b 个在区间 [2,n1] 内的整数 i 满足 pi1>pi,pi<pi+1 (local minimum)

如果存在这样的排列,输出它们中的任意一个,如果不存在,输出 1

分析

考虑何时存在这样的排列。数列单调性不变时,既不会出现local maximum也不会出现local minimum,若数列单调性改变,那么必然出现它们中的一个。两个local maximum之间单调性一定发生了改变,所以必然会出现一个local minimum,同理两个local minimum之间也一定会有一个local maximum,所以 |ab|1 。由于区间 [2,n1] 总共有 n2 个不同整数,所以 a+bn2

再考虑存在时如何构造

  • a<b ,可以构造:

    2,1,4,3,,2a+2,2a1,2a+3,2a+4,,n1,n

  • ab ,设 t=nab2 ,可以构造:

    1,2,,t,t+1,t+1+a+b+32,t+2,t+2+a+b+32,

奇偶讨论后容易证明这两种构造是满足条件的

#include<bits/stdc++.h>
using namespace std;

int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);
    int t;
    cin >> t;
    while(t--) {
        int n, a, b;
        cin >> n >> a >> b;
        if(a + b + 2 > n || abs(a - b) > 1) {
            cout << -1 << endl;
            continue;
        }
        if(a >= b) {
            for(int i = 1; i <= n - a - b - 2; i++)
                cout << i << ' ';
            for(int i = 1; i <= a + b + 2; i++)
                cout << n - a - b - 2 + (i & 1 ? (i + 1) >> 1 : (i >> 1) + (a + b + 3) / 2) << ' ';
        } else {
            for(int i = 1; i <= 2 * a + 2; i++)
                cout << (i & 1 ? i + 1 : i - 1) << ' ';
            for(int i = 2 * a + 3; i <= n; i++)
                cout << i << ' ';
        }   
        cout << endl;
    }
    return 0;
}

CF1650D.Twist the Permutation

题目链接CF1650D

题意

题目较复杂,参考原文

分析

给定了经过 n 轮后的数组,那么我们考虑第 i1 轮数组如何变为第 i 轮数组。可以发现若 i 在第 i 轮数组中的位置为 j ,那么第 i1 轮数组只要对 i 进行 j 次转换即可得到这一结果。所以 i 依次从 n 取到 1 ,每次都可以判定第 i1 轮数组到第 i 轮数组用了多少次转换,之后再还原回第 i1 轮数组,重复这一过程即可

#include<bits/stdc++.h>
using namespace std;

int ans[2000 + 5];
int a[2000 + 5];

int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);
    int t;
    cin >> t;
    while(t--) {
        memset(ans, 0, sizeof(ans));
        int n;
        cin >> n;
        for(int i = 1; i <= n; i++)
            cin >> a[i];
        for(int i = n; i >= 1; i--) {
            int idx;
            for(int j = 1; j <= i; j++) {
                if(a[j] == i) {
                    idx = j;
                    break;
                }
            }
            vector<int> v;
            for(int j = 1; j <= i - 1; j++) 
                v.push_back(a[(idx + j - 1) % i + 1]);
            for(int j = 0; j < i - 1; j++)
                a[j + 1] = v[j];
            ans[i] = (idx == i ? 0 : idx);
        }
        for(int i = 1; i <= n; i++)
            cout << ans[i] << ' ';
        cout << endl;
    }
    return 0;
}

CF1635C.Differential Sorting

题目链接CF1635C

题意

给定一个长度为 n 的数组 a ,可以执行如下操作:

  • 任取三个整数 x,y,z(1x<y<zn) ,使 ax=ayaz

求如何操作能使数组变为非减序列,即 i,aiai+1

不要求操作数最小

分析

考虑序列的最后三个数 an,an1,an2 ,由上述规则可知 an1an 无法更改,如果 an1>an ,那么无论怎么操作都不可能使序列非减

如果 an1an

  • an0 时我们可以遵循一个简单的策略:i=n2,n3,1 时依次执行操作 (x,y,z)=(i,i+1,n) ,那么 ai=ai+1anai+1
  • an<0an2 只有在 an2an1 才可保证序列非减,否则 an2=an1an>an1 ,同理可推 an3,an4,a1 ,所以只有原序列满足非减时才能进行 0 次操作,否则无论如何操作都不可能使序列非减
#include<bits/stdc++.h>
using namespace std;

const int MAX_N = 200000 + 5;
long long a[MAX_N];
int n;

struct node {
    int x, y, z;
} step[MAX_N];

int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);
    int t;
    cin >> t;
    while(t--) {
        cin >> n;
        for(int i = 1; i <= n; i++)
            cin >> a[i];
        if(a[n - 1] > a[n]) {
            cout << -1 << endl;
        } else {
            int cnt = 0;
            bool fnd = true;
            for(int i = n - 2; i >= 1; i--) {
                if(a[i] > a[i + 1]) {
                    if(a[n] >= 0) {
                        a[i] = a[i + 1] - a[n];
                        step[++cnt] = {i, i + 1, n};
                    } else {
                        fnd = false;
                        break;
                    }
                }
            }
            if(fnd) {
                cout << cnt << endl;
                for(int i = 1; i <= cnt; i++) 
                   cout << step[i].x << ' ' << step[i].y << ' ' << step[i].z << endl;
            } else {
                cout << -1 << endl;
            }
        }
    }
    return 0;
}

CF1634C.OKEA

题目链接CF1634C

题意

给定两个整数 n,k 构造一个 n×k 的矩阵 a ,满足:

  • 1nk 的每个整数都出现在矩阵上且仅出现一次
  • 对于任意 i,l,r 满足 ai,l,ai,l+1,,ai,r 的算术平均值是整数

分析

可以发现任意一行内的奇偶性是相同的,如果一行内既存在奇数又存在偶数,那么一定存在一个奇偶相邻的情况,它们的算术平均值不是整数

若每行的奇偶性都相同,那么可以构造:

[132k1242k2k+12k+34k1]

对任意一段 i,l,r 进行求和,可以用等差数列求和公式,可以发现和一定是 l+r1 的倍数,那么算术平均值也一定是整数。进一步,可以求出通项公式 ai,j=2(j+ki12)imod2

#include<bits/stdc++.h>
using namespace std;

int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);
    int t;
    cin >> t;
    while(t--) {
        int n, k;
        cin >> n >> k;
        if((n % 2 && k == 1) || n % 2 == 0) {
            cout << "YES" << endl;
            for(int i = 1; i <= n; i++) {
                for(int j = 1; j <= k; j++)
                    cout << 2 * ((i - 1) / 2 * k + j) - i % 2 << ' ';
                cout << endl;
            }
        } else {
            cout << "NO" << endl;
        }
    }
    return 0;
}

CF1562C.Rings

题目链接:CF1562C

题意

给定一个长度为 n 的字符串,用 f(l,r) 表示子串 slsl+1sr1sr 代表的二进制数,判断是否存在 (l1,r1),(l2,r2) 使得 kN,f(l1,r1)=kf(l2,r2)

l1,r1,l2,r2 需要满足 r1l1+1n2,r2l2+1n2

分析

如果存在 in2+1,si=0 ,那么 f(1,i)=2f(1,i1) 满足条件

否则 in2+1,si=1 ,此时若 sn2=1 ,可以取 f(n2,2n21)=f(n2+1,2n2) ,若 sn2=0 ,可以取 f(n2,2n2)=f(n2+1,2n2)

#include<bits/stdc++.h>
using namespace std;

int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);
    int t;
    cin >> t;
    while(t--) {
        int n;
        string s;
        cin >> n >> s;
        s = ' ' + s;
        bool fnd = false;
        for(int i = n / 2 + 1; i <= n; i++) {
            if(s[i] == '0') {
                cout << 1 << ' ' << i << ' ' << 1 << ' ' << i - 1 << endl;
                fnd = true;
                break;
            }
        }
        if(!fnd) {
            int m = n / 2;
            cout << m << ' ' << 2 * m - (s[m] == '1') << ' ' << m + 1 << ' ' << 2 * m << endl;
        }
    }
}

CF1614B.Divan and a New Project

题目链接CF1614B

题意

数轴上有 n+1 个整点 x0,x1,,xn ,此时你位于 x0 。给定 a1,a2,,an ,求:

2min{i=1nai|x0xi|}

分析

不妨设 x0=0 ,有一个显然的贪心策略:对 a1,a2,,an 从大到小排序,对于较大的 ai 我们使 xi 的绝对值尽量小,这样对答案的贡献也会更小

#include<bits/stdc++.h>
using namespace std;

struct node {
    int val, idx;
} a[200000 + 5];
int x[200000 + 5];

bool cmp(node n1, node n2)
{
    return n1.val > n2.val;
}

int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);
    int t;
    cin >> t;
    while(t--) {
        int n;
        long long sum = 0;
        cin >> n;
        for(int i = 1; i <= n; i++) {
            a[i].idx = i;
            cin >> a[i].val;
        }
        sort(a + 1, a + n + 1, cmp);
        for(int i = 1; i <= n; i++) {
            x[a[i].idx] = (i & 1 ? (i + 1) >> 1 : -(i >> 1));
            sum += 1ll * abs(x[a[i].idx]) * a[i].val;
        }
        cout << 2ll * sum << endl;
        x[0] = 0;
        for(int i = 0; i <= n; i++)
            cout << x[i] << ' ';
        cout << endl;
    }
    return 0;
}
posted @   f(k(t))  阅读(101)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
点击右上角即可分享
微信分享提示