Codeforces Round #598 (Div. 3) codeforces 1256

题目链接

昨天晚上的cf,和程磊开黑打的,听说div3好上分,本来还指望这场上130分直接把颜色改了,没想到翻车了......就过了俩题,A和D过了,B题是个贪心,没写好。

A水题。

B:

题意:给你一个n的全排列,你可以操作n-1次(或者少于n-1次),问操作完后使字典序最小,输出这个字典序最小的排列。对于每种操作,你可以选一个数i(1

思路:每次把要操作的区间的最小值找出来,然后把他弄到区间的最前面,然后区间往右推移,直到结束。

这种题,我总是思路不太清晰,边码边写,弄得很乱,调不出来。还是应该先把思路弄清再写!

#include
#define mem(a,b) memset((a),b,sizeof(a))
#define de cout<a[i])
        {
            minn=a[i];
            q=i;
        }
    }
    if(minn==ans[p])
        {p++;return ;}
    for(int i=q-1;i>=p;i--)
        ans[i+1]=a[i];
    ans[p]=minn;
    p=q;
    for(int i=1;i<=q;i++)
        a[i]=ans[i];
    return ;
}
int main()
{
    int T;scanf("%d",&T);
    while(T--)
    {
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
            scanf("%d",&a[i]),b[a[i]]=i;
        p=-1;
        for(int i=1;i<=n;i++)
            if(b[i]!=i)
                {p=i;break;}
        mem(ans,0);
        for(int i=1;i<=p-1;i++)
            ans[i]=a[i];
        if(p==-1)
            {print(a);continue;}
        while(1)
        {
            if(p>n)    break;
            solve();
        }
        print(ans);
    }
    return 0;
}

C:

题意:一个人位于0号位置,现在要跳到n+1号位置,每次跳跃能从x跳跃到x+1~x+d。给出m块木板的长度,现在要你安排这m块木板的位置(不改变相对顺序,并且不能重叠),输出最后的方案,或者这个人不能成功到n+1点。

思路:先判断用这m个板最多能走多远,如果这个最远路程还比n小,那就输出NO,否则就是YES。然后算出最远能走的路程和n的差值,这个差值就是你可以“浪费”的步数,然后尽可能早的把这些步数浪费掉,然后下面的按照最远的走法走就行了。(最远的走法既是每块隔板间隔d-1的距离)

#include
#define mem(a,b) memset((a),b,sizeof(a))
#define de cout<0)
    {
        if(p>=d-1)
            {p-=d-1,ans[++cnt]=d-1;continue;}
        ans[++cnt]=p;
        p=0;
    }
    print();
    return 0;
}

D:

题意:给出一个0101串,现在执行一次操作为:交换两个相连位置的字符。最多执行k次操作,输出最终得到的字典序最小串。这个题可以重复操作相同位置,这一点和B不一样。

思路:实际上这个还是比较好想的。

#include
#define mem(a,b) memset((a),b,sizeof(a))
#define de cout<

E:

题意:这个学校里面有n个学生,你需要给他们分成若干的队伍,每个队伍最少3个人。每个队伍定义差异值是这个队伍最强的人和最弱的人的能力值差。现在你需要构建若干个队伍,使得差异值的总和最小。

思路:首先排序。然后每个队伍一定人数最多为5个人,因为6个人就可以拆成两队,然后两队的代价一定是比一个队伍的代价小。这一点想到就非常简单了,dp就行了,然后回溯找分配方案。

#include
#define mem(a,b) memset((a),b,sizeof(a))
#define de cout<=8)
            dp[i]=min(min(dp[i-3]+a[i].v-a[i-2].v,dp[i-4]+a[i].v-a[i-3].v),dp[i-5]+a[i].v-a[i-4].v);
        else if(i>=7)
            dp[i]=min(dp[i-3]+a[i].v-a[i-2].v,dp[i-4]+a[i].v-a[i-3].v);
        else
            dp[i]=dp[i-3]+a[i].v-a[i-2].v;
    }
    printf("%I64d ",dp[n]);
    ans=0;
    for(int i=n;i>=3;i--)
    {
        if(i>=5&&dp[i]==dp[i-5]+a[i].v-a[i-4].v)
            a[i].idd=++ans,a[i-1].idd=ans,a[i-2].idd=ans,a[i-3].idd=ans,a[i-4].idd=ans,i-=4;
        else if(i>=4&&dp[i]==dp[i-4]+a[i].v-a[i-3].v)
            a[i].idd=++ans,a[i-1].idd=ans,a[i-2].idd=ans,a[i-3].idd=ans,i-=3;
        else if(i>=3&&dp[i]==dp[i-3]+a[i].v-a[i-2].v)
            a[i].idd=++ans,a[i-1].idd=ans,a[i-2].idd=ans,i-=2;
    }
    printf("%d\n",ans);
    sort(a+1,a+n+1,cmp2);
    printf("%d",a[1].idd);
    for(int i=2;i<=n;i++)
        printf(" %d",a[i].idd);
    puts("");
    return 0;
}

F:

题意:现在给你两个字符串,你可以进行任意次操作。每次操作需要在每个字符串都选择出长度为len的一个区间,然后将这个区间的字符都进行翻转。问你进行若干次操作后,这俩字符串能变成一样的吗?

思路:看了大佬的博客,感觉很妙。

按照这个顺序进行判断:

  1. 如果两个字符串存在不同的字符,那么肯定是NO
  2. 如果某个字符串存在两个相同的字符,那么一定是YES,因为可以就在这两个字符中进行无限次的翻转
  3. 如果两个字符串的逆的奇偶性相同,那么一定是YES

第三个怎么理解呢?在判断1和2之后,我们得到的一定是一个排列,问题就变成你可以翻转若干次,两个排列能否相同。

我们考虑我们同时翻转相同长度的,我们排列的逆一定会发生奇偶性的变化,那么如果一开始奇偶性就不同,那么不管怎么翻转,都不会相同。

推荐参考博客:https://www.cnblogs.com/qscqesze/p/11799050.html

#include
#define mem(a,b) memset((a),b,sizeof(a))
#define de cout<1||cnt2[i]>1)
                {ff++;break;}
        if(ff)  {printf("YES\n");continue;}
        ll sum1=0,sum2=0;
        for(int i=1;i<=n;i++)
            for(int j=i+1;j<=n;j++)
                if(a[i]>a[j])
                    sum1++;
        for(int i=1;i<=n;i++)
            for(int j=i+1;j<=n;j++)
                if(b[i]>b[j])
                    sum2++;
        if((sum1%2)==(sum2%2))
            printf("YES\n");
        else
            puts("NO");
    }
    return 0;
}

 

你可能感兴趣的:(CF,HDU,POJ,题目)