构造组题(一) 热身题 构造 dfs 数学 板子题 水题 字符串 模拟 连通块

专题:构造 Constructive Algorithm

写在前面(作者:PSJ)

构造类题目需要构造方案满足题目条件,或者构造算法在特定限制条件下完成任务。这类题目在 CF、AGC和POI中出现频率很高,下面给出的题目很多都是CF的。
构造算法的一些特点:题目很小巧,代码很短,思路很奇妙;规律性强,打表有机可乘;用数据范围和特点得到简单做法;和很多其他算法杂糅。
还有一个特点:可以出七合一毒瘤题
鉴于第一个特点,所以下面的题目会比较多......

因为构造题考察的重点以思维为主,一旦能凑出解法就已经完成了问题的绝大部分,所以Peter并不会有太多的分析。为了防止篇幅过小就以组题的形式开博客吧!

惯例,组题(一)传送门:(注:2019年Peter的博客写法/格式会有一些变化,我jio得更新是正常的,大家相互理解一下)

 

CF359B Permutation

P3557 [POI2013]GRA-Tower Defense Game

CF989C A Mist of Florescence

AT2043 AND Grid

 

第一部分的题真的对像我这样的萌新很友好,热身题名不虚传啊QAQ

1.CF359B Permutation (小蒟蒻实在是不会用TinyMCE,公式将就着看好吧O(∩_∩)O谢谢)

由题意可知,给出整数n,k,构造一个长度为2n的排列a满足:

i=1na2i- a2i-1 - i=1a2i - a2i-1∣ = 2 * k.

 

一句很牛的话:考虑贡献(这句话曾经浪费了我多少个日夜hhhhh)

分析式子的性质,发现左边式子的两个部分只有绝对值位置是有区别的.假设所有的a2i - a2i-1符号都相同,显然左边的两个式子会互相抵消,最终变为我天天爆的那个数(是ling没错了).

而假设每对都为正数,我将其中一对进行交换,a2i - a2i-1的值显然会变为原来的相反数,即产生 2 * a2i - a2i-1∣ 的贡献.

 

思考到这里,难度直线上升,如何构造 2 * k 呢?

(内心奔腾过1w头草泥马)

考虑特殊构造.

 

造……造……

回到PSJ聚聚说的"用数据范围和特点得到简单做法"

数据范围?

02kn???

cnm

显然,不需要特殊构造了嘤嘤嘤

首先搞个递增序列1~2n,再交换相邻的值,每次交换产生 2 * [ ( x + 1 ) - x ] = 2 * 1 = 2 的贡献,一共交换k次,搞定!

T1到此结束,代码见文末代码块1.

 

2.P3557 [POI2013]GRA-Tower Defense Game

题意:给出一张N个点,M条无向边的图,保证可以在这张图上选出K个点,使得距离每一个点最近的选出的点到它的距离不超过1。现在请你选择不超过K个点,使得距离每一个点最近的选出的点到它的距离不超过2。

可做性:因为题意有1个单位距离的保证,因此2个单位距离的点集一定小于等于1个单位距离的点集,故可做.

又因为此条件,所以找到1个塔的1单位距离以内的所有塔都分别能笼罩自己1个单位距离内的塔,因此采用深度优先遍历.

枚举1~n个点,每次走到一个新的点检查是否走过,如未走过即打上标记,将其加入答案集合,同时对该点周围1个单位距离的塔遍历一遍,均可打上标记.

然后有不超过2的限制,因此可以再将每个距离为1的塔周围距离为1的塔(即与刚刚选中的塔距离为2的塔)遍历一遍打上标记,那么就能够符合题目的限制了.

将n个点都枚举完之后,主体也就完成了,直接输出答案集合即可.

T2到此结束,代码见文末代码块2.(jie个题窝可能语言不是很清晰,欢迎评论区提问)

 

3.CF989C A Mist of Florescence

题意:构造一个不大于50×50的矩阵,其中只有A,B,C,D四种字符,要求A,B,C,D四个字符形成的四连通块个数恰好分别为a,b,c,d.

这里有一个构造的常用套路:充分利用所给资源!!!

比如这道题给出了最大为50*50的矩阵,那么我们每个答案都构造50*50的矩阵,这样我们施展的空间更大,更加方便操作.

首先,因为各个字母至少有1个连通块,我们可以弄出一个下面这样的原始矩阵:

AAAAAAAAAAAAAAAAAAAAAAAAABBBBBBBBBBBBBBBBBBBBBBBBB
AAAAAAAAAAAAAAAAAAAAAAAAABBBBBBBBBBBBBBBBBBBBBBBBB
AAAAAAAAAAAAAAAAAAAAAAAAABBBBBBBBBBBBBBBBBBBBBBBBB
AAAAAAAAAAAAAAAAAAAAAAAAABBBBBBBBBBBBBBBBBBBBBBBBB
AAAAAAAAAAAAAAAAAAAAAAAAABBBBBBBBBBBBBBBBBBBBBBBBB
AAAAAAAAAAAAAAAAAAAAAAAAABBBBBBBBBBBBBBBBBBBBBBBBB
AAAAAAAAAAAAAAAAAAAAAAAAABBBBBBBBBBBBBBBBBBBBBBBBB
AAAAAAAAAAAAAAAAAAAAAAAAABBBBBBBBBBBBBBBBBBBBBBBBB
AAAAAAAAAAAAAAAAAAAAAAAAABBBBBBBBBBBBBBBBBBBBBBBBB
AAAAAAAAAAAAAAAAAAAAAAAAABBBBBBBBBBBBBBBBBBBBBBBBB
AAAAAAAAAAAAAAAAAAAAAAAAABBBBBBBBBBBBBBBBBBBBBBBBB
AAAAAAAAAAAAAAAAAAAAAAAAABBBBBBBBBBBBBBBBBBBBBBBBB
AAAAAAAAAAAAAAAAAAAAAAAAABBBBBBBBBBBBBBBBBBBBBBBBB
AAAAAAAAAAAAAAAAAAAAAAAAABBBBBBBBBBBBBBBBBBBBBBBBB
AAAAAAAAAAAAAAAAAAAAAAAAABBBBBBBBBBBBBBBBBBBBBBBBB
AAAAAAAAAAAAAAAAAAAAAAAAABBBBBBBBBBBBBBBBBBBBBBBBB
AAAAAAAAAAAAAAAAAAAAAAAAABBBBBBBBBBBBBBBBBBBBBBBBB
AAAAAAAAAAAAAAAAAAAAAAAAABBBBBBBBBBBBBBBBBBBBBBBBB
AAAAAAAAAAAAAAAAAAAAAAAAABBBBBBBBBBBBBBBBBBBBBBBBB
AAAAAAAAAAAAAAAAAAAAAAAAABBBBBBBBBBBBBBBBBBBBBBBBB
AAAAAAAAAAAAAAAAAAAAAAAAABBBBBBBBBBBBBBBBBBBBBBBBB
AAAAAAAAAAAAAAAAAAAAAAAAABBBBBBBBBBBBBBBBBBBBBBBBB
AAAAAAAAAAAAAAAAAAAAAAAAABBBBBBBBBBBBBBBBBBBBBBBBB
AAAAAAAAAAAAAAAAAAAAAAAAABBBBBBBBBBBBBBBBBBBBBBBBB
AAAAAAAAAAAAAAAAAAAAAAAAABBBBBBBBBBBBBBBBBBBBBBBBB
CCCCCCCCCCCCCCCCCCCCCCCCCDDDDDDDDDDDDDDDDDDDDDDDDD
CCCCCCCCCCCCCCCCCCCCCCCCCDDDDDDDDDDDDDDDDDDDDDDDDD
CCCCCCCCCCCCCCCCCCCCCCCCCDDDDDDDDDDDDDDDDDDDDDDDDD
CCCCCCCCCCCCCCCCCCCCCCCCCDDDDDDDDDDDDDDDDDDDDDDDDD
CCCCCCCCCCCCCCCCCCCCCCCCCDDDDDDDDDDDDDDDDDDDDDDDDD
CCCCCCCCCCCCCCCCCCCCCCCCCDDDDDDDDDDDDDDDDDDDDDDDDD
CCCCCCCCCCCCCCCCCCCCCCCCCDDDDDDDDDDDDDDDDDDDDDDDDD
CCCCCCCCCCCCCCCCCCCCCCCCCDDDDDDDDDDDDDDDDDDDDDDDDD
CCCCCCCCCCCCCCCCCCCCCCCCCDDDDDDDDDDDDDDDDDDDDDDDDD
CCCCCCCCCCCCCCCCCCCCCCCCCDDDDDDDDDDDDDDDDDDDDDDDDD
CCCCCCCCCCCCCCCCCCCCCCCCCDDDDDDDDDDDDDDDDDDDDDDDDD
CCCCCCCCCCCCCCCCCCCCCCCCCDDDDDDDDDDDDDDDDDDDDDDDDD
CCCCCCCCCCCCCCCCCCCCCCCCCDDDDDDDDDDDDDDDDDDDDDDDDD
CCCCCCCCCCCCCCCCCCCCCCCCCDDDDDDDDDDDDDDDDDDDDDDDDD
CCCCCCCCCCCCCCCCCCCCCCCCCDDDDDDDDDDDDDDDDDDDDDDDDD
CCCCCCCCCCCCCCCCCCCCCCCCCDDDDDDDDDDDDDDDDDDDDDDDDD
CCCCCCCCCCCCCCCCCCCCCCCCCDDDDDDDDDDDDDDDDDDDDDDDDD
CCCCCCCCCCCCCCCCCCCCCCCCCDDDDDDDDDDDDDDDDDDDDDDDDD
CCCCCCCCCCCCCCCCCCCCCCCCCDDDDDDDDDDDDDDDDDDDDDDDDD
CCCCCCCCCCCCCCCCCCCCCCCCCDDDDDDDDDDDDDDDDDDDDDDDDD
CCCCCCCCCCCCCCCCCCCCCCCCCDDDDDDDDDDDDDDDDDDDDDDDDD
CCCCCCCCCCCCCCCCCCCCCCCCCDDDDDDDDDDDDDDDDDDDDDDDDD
CCCCCCCCCCCCCCCCCCCCCCCCCDDDDDDDDDDDDDDDDDDDDDDDDD
CCCCCCCCCCCCCCCCCCCCCCCCCDDDDDDDDDDDDDDDDDDDDDDDDD
CCCCCCCCCCCCCCCCCCCCCCCCCDDDDDDDDDDDDDDDDDDDDDDDDD

A从(1,1)排到(25,25),B从(1,26)排到(25,50),C从(26,1)排到(50,25)D从(26,26)排到(50,50),这样就为每个字母分别创造了一个连通块.

然后呢?

有思路了吗?

Very easy!

比如A,其连通块每增加一个,就可以在D区域内将一个指定位置的D替换成A,周围不放置除了D以外的任何字母(这也就意味着其必须隔行隔列地放在D的内部),这就实现了所有的A目标.

同理,在A中填充D,在C中填充B,在B中填充C,完成所有的任务.

这题按道理在处理上还有一些小的细节可以说道说道,但是由于Peter是一遍过的,所以不知道有哪些易错的细节,欢迎评论区出手:D.

T3到此结束,代码见文末代码块3.

 

4.AT2043 AND Grid

题意:给出一个H×W的图,其中一些格子被标记了。现在请你构造两个H×W的图,满足:①两个图中被标记的格子四连通;②同时在两个图上被标记的格子的集合等同于给出的图上被标记的格子的集合。

原理类似T3,只不过这题的要求不太相同,是两幅图.

题目的核心就是两幅图的并集必须在同一个四连通块内,交集只能与原图相同.

回到PSJ聚聚说的"用数据范围和特点得到简单做法"

特……特……特点?

数据范围:3≤H,W≤ 500,保证给出原图中的最外围一圈一定没有被标记。

好嘛,这题做完了(求导,秒掉)

T4到此结束,代码见文末代码块4.

 

 

 

 

 

 

 

 

 


 

不闹了,接着说T4.

先考虑连通条件和除原图以外无交条件.

比如一个6*5的矩阵:(数字代表第几张图)

1 1 1 1 1 2

1 2 2 2 2 2

1 1 1 1 1 2

1 2 2 2 2 2

1 1 1 1 1 2

看懂了吗?

就像两把梳子一样相互咬合,最左边一列全填1,最右边一列全填2,除这两列以外按行考虑,奇数行填1,偶数行填2.

然后那还不是随心所欲地在两幅图上全填一遍原图?

mzz

搞定!

T4到此结束,代码见文末代码块4.

 

Na么,组题(一)就讲完了,感觉如何?Warm up了没?

好啦,下次见!

完结撒花!

 

 

 

 

 

 

 

 

 


 

 

真没了,回去吧

 

 

 

 

 

 

 

 

 


说了没了你还来,这下被发现了吧
#include<bits/stdc++.h>
using namespace std;
inline int read()
{
    int ret=0,f=1;
    char ch=getchar();
    while(ch>'9'||ch<'0')
    {
        if(ch=='-')
            f=-1;
        ch=getchar();
    }
    while(ch>='0'&&ch<='9')
    {
        ret=(ret<<1)+(ret<<3)+ch-'0';
        ch=getchar();
    }
    return ret*f;
}
int n,k,a[100001],db;
int main()
{
    n=read();
    k=read();
    db=n*2;
    for(register int i=1;i<=db;i++)
        a[i]=i;
    for(register int i=1;i<=k;i++)
        swap(a[i*2-1],a[i*2]);
    for(register int i=1;i<=db;i++)
        printf("%d ",a[i]);
    return 0;
}
T1
 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 inline int read()
 4 {
 5     int ret=0,f=1;
 6     char ch=getchar();
 7     while(ch>'9'||ch<'0')
 8     {
 9         if(ch=='-')
10             f=-1;
11         ch=getchar();
12     }
13     while(ch>='0'&&ch<='9')
14     {
15         ret=(ret<<1)+(ret<<3)+ch-'0';
16         ch=getchar();
17     }
18     return ret*f;
19 }
20 int n,m,k,x,y,ans[500005],num,head[5000005];
21 bool vis[500005];
22 struct edge
23 {
24     int ver;
25     int nxt;
26 }e[2000005];
27 inline void add(int x,int y)
28 {
29     e[++num].ver=y;
30     e[num].nxt=head[x];
31     head[x]=num;
32 }
33 int main()
34 {
35     n=read();
36     m=read();
37     k=read();
38     for(register int i=1;i<=m;i++)
39     {
40         x=read();
41         y=read();
42         add(x,y);
43         add(y,x);
44     }
45     for(register int i=1;i<=n;i++)
46     {
47         if(!vis[i])
48         {
49             ans[++ans[0]]=i;
50             vis[i]=1;
51             for(register int j=head[i];j;j=e[j].nxt)
52             {
53                 vis[e[j].ver]=1;//所有距离为1的塔
54                 for(register int k=head[e[j].ver];k;k=e[k].nxt)
55                     vis[e[k].ver]=1;//所有距离为2的塔
56             }
57         }
58     }
59     printf("%d\n",ans[0]);
60     for(register int i=1;i<=ans[0];i++)
61         printf("%d ",ans[i]);
62     return 0;
63 }
T2
 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 inline int read()
 4 {
 5     int ret=0,f=1;
 6     char ch=getchar();
 7     while(ch>'9'||ch<'0')
 8     {
 9         if(ch=='-')
10             f=-1;
11         ch=getchar();
12     }
13     while(ch>='0'&&ch<='9')
14     {
15         ret=(ret<<1)+(ret<<3)+ch-'0';
16         ch=getchar();
17     }
18     return ret*f;
19 }
20 int a,b,c,d,ans[51][51],nowx,nowy;
21 int main()
22 {
23     a=read();
24     b=read();
25     c=read();
26     d=read();
27     for(register int i=1;i<=25;i++)
28     {
29         for(register int j=1;j<=25;j++)
30             ans[i][j]='A';
31     }
32     for(register int i=1;i<=25;i++)
33     {
34         for(register int j=26;j<=50;j++)
35             ans[i][j]='B';
36     }
37     for(register int i=26;i<=50;i++)
38     {
39         for(register int j=1;j<=25;j++)
40             ans[i][j]='C';
41     }
42     for(register int i=26;i<=50;i++)
43     {
44         for(register int j=26;j<=50;j++)
45             ans[i][j]='D';
46     }
47     nowx=27;
48     nowy=27;
49     for(register int i=1;i<=a-1;i++)
50     {
51         ans[nowx][nowy]='A';
52         if(nowy<49)
53             nowy+=2;
54         else
55             nowy=27,nowx+=2;
56     }
57     nowx=2;
58     nowy=2;
59     for(register int i=1;i<=d-1;i++)
60     {
61         ans[nowx][nowy]='D';
62         if(nowy<24)
63             nowy+=2;
64         else
65             nowy=2,nowx+=2;
66     }
67     nowx=2;
68     nowy=27;
69     for(register int i=1;i<=c-1;i++)
70     {
71         ans[nowx][nowy]='C';
72         if(nowy<49)
73             nowy+=2;
74         else
75             nowy=27,nowx+=2;
76     }
77     nowx=27;
78     nowy=2;
79     for(register int i=1;i<=b-1;i++)
80     {
81         ans[nowx][nowy]='B';
82         if(nowy<24)
83             nowy+=2;
84         else
85             nowy=2,nowx+=2;
86     }
87     printf("50 50\n");
88     for(register int i=1;i<=50;i++)
89     {
90         for(register int j=1;j<=50;j++)
91             printf("%c",ans[i][j]);
92         printf("\n");
93     }
94     return 0;
95 }
T3
 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 inline int read()
 4 {
 5     int ret=0,f=1;
 6     char ch=getchar();
 7     while(ch>'9'||ch<'0')
 8     {
 9         if(ch=='-')
10             f=-1;
11         ch=getchar();
12     }
13     while(ch>='0'&&ch<='9')
14     {
15         ret=(ret<<1)+(ret<<3)+ch-'0';
16         ch=getchar();
17     }
18     return ret*f;
19 }
20 int h,w,ans1[501][501],ans2[501][501];
21 int main()
22 {
23     h=read();
24     w=read();
25     for(register int i=1;i<=h;i++)
26     {
27         for(register int j=1;j<=w;j++)
28             scanf("%c",&ans1[i][j]),ans2[i][j]=ans1[i][j];
29         getchar();
30     }
31     for(register int i=1;i<=h;i+=2)
32     {
33         for(register int j=1;j<w;j++)
34             ans1[i][j]='#';
35     }
36     for(register int i=2;i<=h;i+=2)
37     {
38         ans1[i][1]='#';
39     }
40     for(register int i=2;i<=h;i+=2)
41     {
42         for(register int j=2;j<=w;j++)
43             ans2[i][j]='#';
44     }
45     for(register int i=1;i<=h;i+=2)
46     {
47         ans2[i][w]='#';
48     }
49     for(register int i=1;i<=h;i++)
50     {
51         for(register int j=1;j<=w;j++)
52             printf("%c",ans1[i][j]);
53         printf("\n");
54     }
55     printf("\n");
56     for(register int i=1;i<=h;i++)
57     {
58         for(register int j=1;j<=w;j++)
59             printf("%c",ans2[i][j]);
60         printf("\n");
61     }
62     return 0;
63 }
T4

转载于:https://www.cnblogs.com/Peter0701/p/10332880.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值