Codeforces Round #580 (Div. 2)赛后总结

本总结仅有A,B,C,D四题,E题作为交互题,不会!

A:Choose Two Numbers 

没啥意思,因为CF只要求任意一组解,并且两个数列均为正整数,那么果断求两个数列最大值之和,这样可以保证最大值之和一定不会存在于原数列中。

#include<iostream>
using namespace std;
int n,m,a1=-998244353,a2=-998244353,k;
int main()
{
    cin>>n;
    for(int i=1;i<=n;i++)
    {
        cin>>k;
        a1=max(a1,k);
    }
    cin>>m;
    for(int i=1;i<=m;i++)
    {
        cin>>k;
        a2=max(a2,k);
    }
    cout<<a1<<' '<<a2;
    return 0;
} 
A

B:Make Product Equal One

这个稍微有点意思了,果断贪心。首先将每个数都先变成离自己最近的±1,也就是正数变成1,负数变成-1,同时记录变成-1数的个数和是否有0的存在。

对于0,先将其变成1。

下面判断-1的个数Mod2是否为0,如果为0直接输出答案,否则看当前是否有0的存在。如果有0的存在,也直接输出,视为将变为1的0变成-1,cost不变。如果没有0的存在,就在原cost的基础上+2,视为将某个1变成-1.

#include<iostream>
#include<cstdio>
using namespace std;
long long int s[100001],ans,mod,mix=998244353,maxx=-998244353,flag=0;
int n;
int main()
{
    cin>>n;
    for(int i=1;i<=n;i++)
    {
        cin>>s[i];
        if(s[i]>=0)
        {
            ans+=max(s[i]-1,1LL*0);
            if(s[i]==0)
            {
                flag=1;
                ans++;
            }
            mix=min(mix,s[i]);
        }
        else
        {
            ans-=s[i]+1;
            maxx=max(maxx,s[i]);
            mod++;
        }
    }
    if(mod%2==0)
    {
        cout<<ans;
        return 0;
    }
    else
    {
        if(flag==1)
        {
            ;
        }
        else
        {
            ans+=2;
        }
        cout<<ans;
        return 0;
    }
}
B

C: Almost Equal

这个更有意思,题意可知要将这些数排成环,保证每连续N个数的和之间的差不超过1.

给出一种神奇的构造方法。假定N=3,一共6个数,分别记作a,a+1,b,b+1,c,c+1.那么a=1,b=3,c=5,

这样可以得知abc三个前缀一定要顺序排列,保证每一份均为a+b+c+x。

并且相邻两个数一定是一个带有+1,一个不带有+1(否则就会出现有一组没有+1,或者有一组3个+1)

则针对N=3的合法排列有 a,b+1,c,a+1,b,c+1;

然后我们发现 这个排列刚好是样例1N=3时给出的答案。

下面我们来考虑怎样判断不可能情况。不可能情况也就是有两个+1连在一起了,也就是N为偶数的情况。

N=4有:a,b+1,c,d+1, a+1,b,c+1,d;

可以截取:d+1---c+1 和 d---c

第一个区间==a+b+c+d+3,第二个区间==a+b+c+d+1

所以,N为偶数的情况不可取

#include<iostream>
#include<cstdio>
using namespace std;
int n,ke[200001],cnt=0;
int main()
{
    cin>>n;
    if(n%2==0)
    {
        cout<<"NO";
        return 0;
    }
    for(int i=1;i<=n;i+=2)
    {
        
        ke[i]=i*2-1;
        ke[i+n]=ke[i]+1;
    }
    for(int i=2;i<=n;i+=2)
    {
        ke[i]=i*2;
        ke[i+n]=ke[i]-1;
    }
    cout<<"YES"<<endl;
    for(int i=1;i<=2*n;i++)
    {
        cout<<ke[i]<<' ';
    }
    return 0;
}
C

D:Shortest Cycle

出题人备注:一个环至少有3个点

这个就有一定的坑爹之处了,众所周知求最小环是N^3的时间复杂度,那如何缩小N?

观察可知,最大的数一共60位,那么如果数字的数量超过2*60,就一定可以保证有3个点两两AND!=0;

假设前60个数在2进制上均为最高位为1,其他位为0,那么这60个数中间没有任意两个数AND!=0。但是这个时候随便来一个二进制少于60位的就一定有至少一对数字AND!=0。这个很容易理解。也很方便就可以类推到3个点。

下面就可以把N拘束在120以内了。Floyd求最小环即可!

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
long long int n=0,vis[100005],t,ans=0x3f3f3f3f,xl;
long long int dis[201][201];
long long int edge[201][201];
long long int a[100005];
int main()
{
    cin>>t;
    //memset(dis,0x3f3f3f3f,sizeof(dis));
    //memset(edge,0x3f3f3f3f,sizeof(edge));
    for(int i=1;i<=t;i++)
    {
        cin>>a[i];
        if(a[i]!=0)
        {
            n++;
            vis[n]=a[i];
        }
    }
    if(n>2*60)
    {
        cout<<3;
        return 0;
    }
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=n;j++)
        {
            if(((vis[i]&vis[j])!=0)&&i!=j)
            {
                dis[i][j]=1;
                edge[i][j]=1;
            }
            else
                dis[i][j]=edge[i][j]=0x3f3f3f3f;
        }
    }
    for(int k=1;k<=n;k++)
    {
        for(int i=1;i<k;i++)
        {
            for(int j=i+1;j<k;j++)
            {
                ans=min(ans,dis[i][j]+edge[i][k]+edge[k][j]);
            }
        }
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=n;j++)
            {
                dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);
            }
        }
    }
    if(ans==0x3f3f3f3f)
    {
        cout<<-1; 
    }
    else
        cout<<ans;
    return 0;
} 
D

完结撒花!

posted @ 2019-08-19 23:37  HA-SY林荫  阅读(237)  评论(0编辑  收藏  举报