构造题

牛客 牛牛的DRB迷宫II

题面:

在这里插入图片描述

思路:

在这里插入图片描述

code:
//https://ac.nowcoder.com/acm/contest/3004/B
#include<bits/stdc++.h>
using namespace std;
const int maxm=55;
char a[maxm][maxm];
signed main(){
    int k;
    cin>>k;
    int n=30+2,m=30;
    a[0][0]='B';//起点必须是B
    for(int i=1;i<m;i++)a[0][i]='D';
    for(int i=1;i<n-1;i++){
        for(int j=0;j<m;j++){
            if(j==i)a[i][j]='B';
            else if(j==i-1)a[i][j]='R';
            else a[i][j]='D';
        }
    }
    for(int i=0;i<m;i++){
        if(k>>i&1)a[i+1][i]='B';//如果这一位是1
        a[n-1][i]='R';//最后一行都是R
    }
    a[n-1][m-1]='D';//终点随便哪个字符都行
    cout<<n<<' '<<m<<endl;
    for(int i=0;i<n;i++)cout<<a[i]<<endl;
    return 0;
}

CodeForces 1088 C.Ehab and a 2-operation task

题意:

给一个长度为n的数组a,(0<=a(i)<=1e5)
你可以进行两种操作:
(1,i,x) 把1-i 的所有数加上x,x必须是非负数
(2,i,x) 把1-i 的所有数对x取模,x必须是整数

现在需要你构造出一组不超过n+1次的操作,使得进行完操作之后数组严格递增

思路:

先把所有数都加上1e5:a[i]+=1e5
然后对于从1到n的 i ,把1-i 取模 a[i]-i,这样之后a[i]就等于 i 了
结束之后的序列就是1-n,满足严格递增

ps:
假设一个数为x,那么我们可以通过选择x/2-x中的某个数k,使得x%k取模后的结果为0-x/2,即可以控制结果

code:
#include<bits/stdc++.h>
using namespace std;
const int maxm=2e5+5;
int a[maxm];
signed main(){
    int n;
    cin>>n;
    for(int i=1;i<=n;i++){
        cin>>a[i];
    }
    cout<<n+1<<endl;
    cout<<1<<' '<<n<<' '<<(int)1e5<<endl;
    for(int i=1;i<=n;i++){
        a[i]+=1e5;
    }
    for(int i=1;i<=n;i++){
        cout<<2<<' '<<i<<' '<<a[i]-i<<endl;
    }
    return 0;
}

CodeForces 1017 C. The Phone Number

题意:

给定n,要求你构造一个1-n的排列,使得排列的LIS+LCS最小

思路:

错误思路:
开始想的是分成两块n/2的,然后前面(n/2+1)-n,后面1-n/2
发现n=9的时候就wa了

正确思路:
首先显然大的块放在前面小的块放在后面,例如34 12
假设分成p块,每块中的数连续且递增
则LIS=p,LCS=n/p
ans=p+n/p
又均值不等式得:p+n/p>=2sqrt(n),可推出当p等于sqrt(n)的时候p+n/p最小
因此取p=sqrt(n),分块输出即可

code:
#include<bits/stdc++.h>
using namespace std;
signed main(){
    int n;
    cin>>n;
    int f=sqrt(n);
    for(int i=n;i>=1;){
        int now=max(i-f+1,1);
        for(int j=now;j<=i;j++){
            cout<<j<<' ';
        }
        i=now-1;
    }
    return 0;
}

CodeForces1278 E. Tests for problem D

题意:

给一颗n个顶点的树
要求构造出n个线段(l,r)
满足:
如果线段i和线段j相交,那么在点i和点j之间建立一条边,
要求建边之后的图就是给定的树

思路:

在这里插入图片描述
图中点2和点3都是点1的子节点,那么2和3的左端点都要大于1的左端点,右端点也要大于1的右端点
但是因为2和3的线段不能相交,因此:
如果2的左端点大于3的左端点
那么2的右端点小于3的右端点
如图,就是构造包含关系,子节点之间的两端大小比较是相反的(左边递增右边递减,或者反过来)

code:
#include<bits/stdc++.h>
using namespace std;
const int maxm=5e5+5;
int l[maxm],r[maxm],tot;
vector<int>g[maxm];
int n;
void dfs(int x,int fa){
    int len=g[x].size();
    for(int i=len-1;i>=0;i--){
        int v=g[x][i];
        if(v==fa)continue;
        l[v]=++tot;
    }
    r[x]=++tot;
    for(int i=0;i<len;i++){
        int v=g[x][i];
        if(v==fa)continue;
        dfs(v,x);
    }
}
signed main(){
    scanf("%d",&n);
    for(int i=1;i<n;i++){
        int a,b;
        scanf("%d%d",&a,&b);
        g[a].push_back(b);
        g[b].push_back(a);
    }
    l[1]=++tot;
    dfs(1,-1);
    for(int i=1;i<=n;i++){
        printf("%d %d\n",l[i],r[i]);
    }
    return 0;
}

CodeForces1325 C. Ehab and Path-etic MEXs

题意:

给一颗n个顶点的树,要求在边权填上0-(n-2)
使得任意点对之间路径的mex最大值最小,输出一组方案

思路:

0和1不管怎么放肯定都在一条链上,接下来考虑2,如果2也在同一条链上,那么mex会变成3
所以要把2分开,做法是找到三个叶子节点填0、1、2,这样他们就不会再同一条链上了。
如果没有三个叶子,也就是树是一条链的话,不管怎么填mex都是n-1,不需要特判
因此找三个叶子填0、1、2,其他随便填填就行了,找叶子节点用度数就行了。
找一个度数为3的点,三个方向各填一个也可以。不过找叶子比这个方便。


CodeForces1328 D. Carousel

题意:

给定一个长度为n的数组a,这n个数围成一圈,
现在要你染色,满足当a(i)!=a(i-1)的时候,两者的颜色必须不同,
问最少要用多少种颜色,且输出一种染色方案

思路:

当所有a(i)相同的时候,全部染成一种颜色即可

当n为偶数的时候,染成1,2,1,2,1,2即可,这样首尾也是1,2

当n为奇数的时候,判断是否存在两个相邻的数,这两个相同,

如果存在,则答案为2,因为可以把这两个位置染成同一种颜色,类似将这两个点缩成一个点,
这样之后n就变成偶数了,继续1,2,1,2,即可

如果不存在,则答案为3,方案为1,2,1,2,…3,最后一个数放3即可。

code:
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int maxm=2e5+5;
int a[maxm];
signed main(){
    int T;
    cin>>T;
    while(T--){
        int n;
        cin>>n;
        map<int,int>mark;
        int ok=0;
        for(int i=1;i<=n;i++){
            cin>>a[i];
            mark[a[i]]=1;
            if(a[i]==a[i-1])ok=i;
        }
        if(a[1]==a[n])ok=1;
        if(mark.size()==1){//只有一种
            cout<<1<<endl;
            for(int i=1;i<=n;i++)cout<<1<<' ';
        }else if(n%2==0){//偶数情况
            cout<<2<<endl;
            for(int i=1;i<=n;i++){
                cout<<i%2+1<<' ';
            }
        }else{//奇数情况
            if(ok){//有相邻相同
                cout<<2<<endl;
                for(int i=1;i<=ok-1;i++){
                    cout<<i%2+1<<' ';
                }
                cout<<(ok-1)%2+1<<' ';
                for(int i=ok+1;i<=n;i++){
                    cout<<(i-1)%2+1<<' ';
                }
            }else{//没有相邻相同
                cout<<3<<endl;
                for(int i=1;i<=n-1;i++){
                    cout<<i%2+1<<' ';
                }
                cout<<3<<' ';
            }
        }
        cout<<endl;
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值