Codeforces Round #580 (Div. 2)

A. Choose Two Numbers

题意:让你从A集合里取一个数a,B集合里也取一个数b,使得a+b同时不存在于集合A和集合B中

思路:直接取A和B集合中最大元素,最大元素相加必然不在A集合或者B集合里

    #include <cstdio>
    #include <algorithm>
    #include <iostream>
    #include <cstring> 
    using namespace std;
    int main()
    {
        int n, m;
        scanf("%d", &n);
        int a[n];
        for (int i = 0; i < n; i++)
            scanf("%d", &a[i]);
        scanf("%d", &m);
        int b[m];
        for (int i = 0; i < m; i++)
            scanf("%d", &b[i]);
         printf("%d %d", *max_element(a, a+n), *max_element(b, b+m));
    }
View Code

 B.Make Product Equal One

题意:给你一段序列,让你经过k次操作后使得这个序列积为1。

思路:统计0的个数,统计小于等于-1的个数,之后分三种情况讨论:

1.负数个数为偶数:直接abs(abs(a[i])-1)遍历一遍即可

2.负数个数为奇数,且有0的存在:直接abs(abs(a[i])-1)遍历一遍即可(因为将要将其中一个-1转成1,0必然是要变成1或-1的所以不用考虑费用)

3.负数个数为奇数数,且0不存在:abs(abs(a[i])-1)遍历一遍之后+2即可(因为将要将其中一个-1转成1

#include <cstdio>
#include <algorithm>
#include <iostream>
#include <cstring>
using namespace std;
int main()
{
    int n;
    scanf("%d", &n);
    int a[n];
    int cnt1 = 0, cnt0 = 0, mminus = 0x3f3f3f3f;
    for (int i = 0; i < n; i++)
    {
        scanf("%d", &a[i]);
        if (a[i] < 0)
        {
            cnt1++;
            if (abs(a[i]) < mminus)
                mminus = a[i];
        }
        if (a[i] == 0) cnt0++;
    }
    if (cnt1 % 2 == 0)
    {
        long long ans = 0;
        for (int i = 0; i < n; i++)
            ans += abs(abs(a[i])-1);
        printf("%lld
", ans);
        return 0;
    }
    else
    {
        if (cnt0)
        {
            long long ans = 0;
            for (int i = 0; i < n; i++)
                ans += abs(abs(a[i])-1);
            printf("%lld
", ans);
            return 0;
        }
        else
        {
            long long ans = 0;
            for (int i = 0; i < n; i++)
                ans += abs(abs(a[i])-1);
            printf("%lld
", ans+2);
        return 0;
        }
    }
}
View Code

C. Almost Equal

题意:给你数字n,让你构造一个由1-2n组成的序列。序列满足每个长度为n的子序列之差不能大于1。

思路:DFS找规律。

规律如下:

偶数直接输出“NO”,奇数的话就拿n=3举例。会发现1对的是2,3对的是4,5对的是6。(左边才是题目正解图)

之后进一步观察发现1XX2XX, 14X23X,145236。奇数偶数交替填入即可。具体看代码。

DFS找规律代码:

#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <set>
using namespace std;
int a[100];
int vis[100];
int n;
int final_check(){
    set<int> s;
    for (int i = 1; i <= 2*n; i++){
        int sum = 0;
        for (int j = 1; j <= n; j++)
            if (i + j > 2*n) sum += a[(i+j)%(2*n)];
            else sum += a[i+j];
        s.insert(sum);
        if (s.size() > 2) return 1;
    }
    return 0;
}

int check(int cur, int goal){
    int temp = cur;
    int sum = 0;
    while (temp > cur-n) sum += a[temp--];
    return abs(sum - goal) > 1;
}

void dfs(int cur){
    if (cur == 2 * n + 1) {
        if (!final_check()){
            for (int i = 1; i <= 2*n; i++) cout << " " << a[i];
            cout << endl;
        } return ;
    }
    for (int i = 1; i <= 2*n; i++){
        if (!vis[i]){
            a[cur] = i;
            if (cur < n) vis[i] = 1, dfs(cur+1), vis[i] = 0;
            else
            {
                int goal = 0;
                for (int j = 1; j <= n; j++) goal += a[j];
                if (!check(cur, goal)) vis[i] = 1, dfs(cur+1), vis[i] = 0;
            }
        }
    }
}

int main(){
    while (~scanf("%d", &n))
        dfs(1);
    return 0;
}
View Code

AC代码:

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn = 200000 + 100;
int n;
int ans[maxn];
int main()
{
    scanf("%d",&n);
    if (n % 2==0)
    {
        printf("NO
");
        return 0;
    }
    int judge = 0, cnt = 0;
    for(int i = 0; i < n; i++)
        if(judge++ % 2 == 0) ans[i] = ++cnt, ans[i+n] = ++cnt;
        else ans[i+n] = ++cnt, ans[i] = ++cnt;
    printf("YES
");
    for(int i = 0; i < 2 * n; i++) printf("%d ", ans[i]);
    printf("
");
}
View Code

D.Shortest Cycle

题意:给n个数,(a[1] - a[n]),如果如果i != j且(a[i] & a[j]) != 0,则在i与j之间建边

求图的最小环(无向图最小环至少三个顶点)

思路:发现题目给的n超级大,那肯定是不能暴力的。观察梯面,发现 ai  <= 1e18 ≈ 2^60。所以就想到当非零的ai数大于120(每一位有1和0两种可能,所以为 60 * 2)时最小环长度必然是3

之后对于n <= 120时直接裸一个最小环即可。

#include<cstdio>
#include<cstring>
#include<iostream>
#include<cmath>
#include<algorithm>
typedef long long ll;
const int inf=9999999;
using namespace std;
const int maxm=1e5+5;
int cnt;
ll a[maxm];
int d[205][205];
int graph[205][205];
int ans=inf;

void floyd(){
    for(int k=1;k<=cnt;k++){
        for(int i=1;i<=k-1;i++)
            for(int j=i+1;j<=k-1;j++)
                ans=min(ans,d[i][j]+graph[i][k]+graph[k][j]);


        for(int i=1;i<=cnt;i++)
            for(int j=1;j<=cnt;j++)
                d[i][j]=min(d[i][j],d[i][k]+d[k][j]);
    }
    if(ans==inf) puts("-1");
    else printf("%d
",ans);
}
int main(){
    int n; cin >> n;
    for (int i = 1; i <= n; i++){
        ll t; cin >> t;
        if(t) a[++cnt]=t;
    }
    if (cnt > 120){
        puts("3");
        return 0;
    }

    for(int i=1;i<=cnt;i++)
        for(int j=i+1;j<=cnt;j++)
            if (a[i]&a[j]) graph[i][j]=graph[j][i]=d[i][j]=d[j][i]=1;
            else graph[i][j]=graph[j][i]=d[i][j]=d[j][i]=inf;
    floyd();
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/Vikyanite/p/11402994.html