A-C

Posted on 2022-12-05 19:38  Capterlliar  阅读(83)  评论(0编辑  收藏  举报

很喜欢做构造题,主要是喜欢那种摸不着头脑的感觉

传送门

A. Make It Connected

题意:给出一张没有重边和自环的图,接下来定义一种操作:选择一个结点v,对于除了这个结点的其他点,如果和v之间原来有边,删除这条边;反之添加一条边。求至少操作几次能使整张图联通。

解:找特殊情况+分类讨论

首先用心感受一下这种操作,是让一个点和原来的连通块断绝连系,然后使剩下的部分联通。如果这个点和原来的连通块中的某个点之间没有边,那么一次操作后就可以满足要求。归纳一下就是,如果存在一个连通块不是完全图,那么1次操作就可以解决;现在假设全部连通块都是完全图,那进行一次操作就是把一个点从一个完全图里剥离出来。如果有超过两个的完全图,那一次操作可以使剩余的完全图不是完全图,从而两次操作后满足要求;如果只有两个完全图,那只能把小的那个删到只有一个结点,然后再操作一次使其满足要求。

B. Rectangular Congruence

题意:给出一个n*n矩阵对角线上的元素,其中n是质数。试在此基础上填完这个矩阵,使得每个子矩阵两对角之和模n不相等。即:

 解:条件变形

给上式移项变形,得出结论:任意两列上位于同一行的两个点,其模n意义下的差两两不相等。让每行相邻两个数的差d相同,行与行之间d取不同值,可取0~n-1,因为n是质数,所以不会同时出现某n的倍数。

C. Equal Binary Subsequences

题意:给出一个01串,定义一种操作:选择01串的一个子序列(subsequence,可为空),将子序列循环右移一格。现执行一次这种操作,问新序列是否能分成两个相同的子序列。

解:分组构造

完全没想出来。将只有两种字符的字符串分成相同的两个子序列,考虑两两相邻分组。如果能分出(0,0),(1,1)这样的组,两个子序列各选一个0或1.如果分出(0,1)这样的组,可以通过循环右移来将其变为(0,0)或(1,1).

具体代码:

#include <bits/stdc++.h>
using namespace std;
#define maxx 200005
#define maxn 25
#define maxm 205
#define ll long long
#define inf 1000000009
#define mod 2520
char a[maxx]={0};
signed main(){
    int T;
    scanf("%d",&T);
    while(T--){
        int n;
        scanf("%d",&n);
        n*=2;
        scanf("%s",a+1);
        for(int i=1;i<=n;i++){
            a[i]-='0';
        }
        int cnt1=0;
        for(int i=1;i<=n;i++){
            if(a[i]==1) cnt1++;
        }
        if(cnt1%2||n%2){
            printf("-1\n");
            continue;
        }
        int now=0;
        vector<int> ans;
        for(int i=1;i<=n;i+=2){
            if(a[i]!=a[i+1]){
                if(a[i]==now) ans.push_back(i);
                else ans.push_back(i+1);
                now=1-now;
            }
        }
        vector<int> ans2;
        now=0;
        for(int i=1;i<=n;i+=2){
            if(a[i]==a[i+1]) ans2.push_back(i);
            else{
                if(a[i]==now) ans2.push_back(i+1);
                else ans2.push_back(i);
                now=1-now;
            }
        }
        printf("%d ",ans.size());
        for(auto i:ans) printf("%d ",i);
        printf("\n");
        for(auto i:ans2) printf("%d ",i);
        printf("\n");
    }
    return 0;
}
View Code