Codeforces Round #813 (Div. 2) (补题中)

战绩:

 

 A. Wonderful Permutation

签到题。

计算前k个就把最小的那k个转移到前k项,看数组前k项缺多少最小前k项就行,可以在O(k)的复杂度内解决。

int main()
{
    read(T);
    while(T--)
    {
        read(n);read(k);
        for(int i=1;i<=n;i++) 
        {
            read(a[i]);
            b[i]=a[i];
        }
        
        sort(a+1,a+1+n);
        int ans=0;
        for(int i=1;i<=k;i++)
        {
            for(int j=1;j<=k;j++)
            {
                if(a[i]==b[j]) break;
                else if(j==k) ans++;
            }
        }
        cout<<ans<<endl;
    }
    return 0;
}
赛时代码复杂度O(k2

O(n复杂度代码):应付n和k的限制可以更大

int main()
{
    cin>>T;
    while(T--)
    {
        int n,k;
        cin>>n>>k;
        int ans=0;
        for(int i=1;i<=n;i++) cin>>a[i];
        for(int i=1;i<=k;i++)if(a[i]>k)ans++;
        cout<<ans<<endl;
    }
}
赛后代码

 B. Woeful Permutation

最大的利用每个数字的lcm就是让两个数字没有除了1以外的公因数也就是两两互质,每个数字n和n-1或者n+1是一定互质的。

题目要求最大,我们就从最后一位开始往前,两两交换数字,这样得到的答案一定是最大的。

int main()
{
    read(T);
    while(T--)
    {
        read(n);
        a[0]=1;
        for(int i=1;i<=n;i++) a[i]=i;
        for(int i=n;i>=1;i--)
        {
            if(i%2==n%2) swap(a[i],a[i-1]);
        }
        for(int i=1;i<=n;i++) cout<<a[i]<<" ";
        cout<<endl;
    }
    return 0;
}
View Code

C. Sort Zero

给定的数字一定是一组正数,我们每次把一种数字变为0,也就意味着这个数字会变成最小的那个。

当某一位变成0之后,我们很容易发现,为了不递减,前面的所有位置都会变为0,所以对原数组一定是保留最后那一节不递减序列。

可以用set维护,实现很快。

int main()
{
    read(T);
    while(T--)
    {
        st.clear();
        read(n);
        for(int i=1;i<=n;i++)
        {
            read(a[i]);
            b[i]=0;
        }
        for(int i=2;i<=n;i++) if(a[i]<a[i-1]) b[i]=1;
        bool flag=1;
        for(int i=n;i>=1;i--)
        {
            if(!flag) st.insert(a[i]);
            else if(b[i]==1) flag=0;
        }
        flag=1;
        for(int i=n;i>=1;i--)
        {
            if(!flag) st.insert(a[i]);
            else if(st.find(a[i])!=st.end()) flag=0;
        }
        cout<<st.size()<<endl;
    }
    return 0;
}
View Code

 有队友试图hack所以多解释两句代码... ...

第一次循环我们保留了最后一节不递减序列,这之前的全部变为0,但是有可能会有和后面数字和前面相同的地方,我们也要变为0,所以再做一遍,将和前面的数字相同的最后一个数字之前变为0.

这个时候新变为0的数字不会再在后面出现,因为我们保留的是一个不递减序列,因此只用再做一次。

 

D. Empty Graph(图论二分)

比赛做的时候就想的是二分,但是题目打着打着猪脑过载,最后交了发WA的屎山代码不想改了。

后来在纸上慢慢推了下思路,发现代码完全不长。

首先明确题意,两点间的路径是在这两个点的区间内最小点的值,我们最后要有一种修改方式,使得所有的两点间的最短距离的最大值尽可能大。

最小值最大类问题,可以率先想到二分法。

我们修改一定是要把某个数字改成1e9.

我们二分一个答案路径长度,看使得答案符合大于等于这个路径需要最少修改

首先我们确定一个最小值点作为中转点,让2*a[i]<二分的答案的点全部都变为1e9,下面解释

对于修改值后的某两个点(u和v)的路径,其中一定有一条是通过最小的点(x)连接的(u->x->v),又有x是最小值,因此这条路的大小就是2*a[x]。

但是这两个点也可以通过直接相连的路到达(由于x最小,通过其他中转点不会比2*a[x]更优)。

对于一个路径(u->x->v)u和v的直接路径实际上是(u->x和x->v)这两段路的最小值。我们只用看相邻的路径。

我们只要保证图里存在一对相邻点,他们的直接路径大于2*a[x],那么答案就会被固定为2*a[x]。

因为这意味着存在这样的两个点,他们的最短路径通过x连接两个点,长度为2*a[x],其他的路径比它小也不会影响答案。

但是如果不存在这样的两个点,我们必须进行修改。

如果存在相邻的两个点a和b,他们一个符合值大于2*a[x],另一个小于2*a[x],我们修改一次,只用修改小的那个。

不存在这样的a和b则修改两次。

比赛代码改的,有点混乱。

#include<iostream> 
#include<cstdio>
#include<string>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<set>
#include<ctime>
#define N 150000
#define ll long long
using namespace std;
ll n,T,k,rec,ans;
struct node
{
    ll val,pos;
}ed[N],a[N];
inline void read(ll &p)
{
    p=0;ll f=1;
    char ch=getchar();
    while(ch<'0'||ch>'9') {if(ch=='-') f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9') p=p*10+(ch-'0'),ch=getchar();
    p*=f;
}

inline bool cmp(node a,node b) {return a.val<b.val;}
inline bool cmp2(node a,node b) {return a.pos<b.pos;}

inline bool jud(ll x)
{
    ll lim=0;
    for(int i=1;i<=n;i++) a[i]=ed[i];
    for(int i=1;i<=n;i++)
    {
        if(2*a[i].val<x){a[i].val=1000000000;lim++;}
    }
    if(lim>k) return 0;
    sort(a+1,a+1+n,cmp2);
    ll f=2;
    for(int i=1;i<n;i++)
    {
        if(a[i].val>=x&&a[i+1].val>=x) f=0;
        if((a[i].val<x&&a[i+1].val>=x)||(a[i+1].val<x&&a[i].val>=x)) {f=min(1ll*1,f);}
    }
    if(lim+f>k) return 0;
    else return 1;
}

int main()
{
    read(T);
    while(T--)
    {
        read(n);read(k);
        for(int i=1;i<=n;i++)
        {
            read(ed[i].val);
            ed[i].pos=i;
        }
        sort(ed+1,ed+1+n,cmp);
        if(n==k) printf("1000000000\n");
        else if(n==2) printf("%lld\n",ed[2].val);
        else
        {
            ans=0;
            ll l=0,r=1e9;
            while(l<=r)
            {
                ll mid=(l+r)>>1;
                if(jud(mid)) {ans=mid;l=mid+1;}
                else r=mid-1;
            }
            printf("%lld\n",ans);
        }
    }
    return 0;
}
View Code

 

posted @ 2022-08-14 11:33  ztlsw  阅读(36)  评论(0编辑  收藏  举报