Codeforces Round #704 (Div. 2) A-E题解

71 篇文章 0 订阅

A Three swimmers
题意 三个人每人游一个来回时间分别是a、b、c,那么在 a、b、c的倍数时间点上 三个人均会在左边的点,题目问你p时刻来 还要等多久最快遇到三个人 1e18 除法判断是否整除相减即可

#include<cstdio>
#include<vector>
#include<cstring>
#include<cmath>
#include<iostream>
#include<queue>
using namespace std;
#define dbg(x) cout<<#x<<" = "<< (x)<< endl
#define dbg2(x1,x2) cout<<#x1<<" = "<<x1<<" "<<#x2<<" = "<<x2<<endl
#define dbg3(x1,x2,x3) cout<<#x1<<" = "<<x1<<" "<<#x2<<" = "<<x2<<" "<<#x3<<" = "<<x3<<endl
const int MAX_N = 100005;
priority_queue<pair<int,int> > q;
int ans[MAX_N],arr[MAX_N];
int num = 0;
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        num = 0;
        int n;
        scanf("%d",&n);
        for(int i = 1;i<=n;++i)
        {
            scanf("%d",&arr[i]);
            q.push(make_pair(arr[i],i));
        }
        int maxx = n;
        while(!q.empty())
        {
            pair<int,int> top = q.top();
            q.pop();
            if(top.second>maxx) continue;
            int xb = top.second;
            while(xb<=maxx)
            {
                ans[++num] = arr[xb];
                xb++;
            }
            maxx = top.second-1;
        }
        for(int i = 1;i<=n;++i)
        {
            i==n?printf("%d\n",ans[i]):printf("%d ",ans[i]);
        }
    }
    return 0;
}

BCard Deck
按照卡牌顺序你每次选k张,然后将k张从最下面反过来放到新桌子上获得收益,收益因为是n的次方,我们发现每个卡牌是小于等于n,所以你把大的放在最下面获得收益最高,如果每个卡牌不是小于等于n 需要dp计算

#include<cstdio>
#include<vector>
#include<cstring>
#include<cmath>
#include<iostream>
#include<queue>
using namespace std;
#define dbg(x) cout<<#x<<" = "<< (x)<< endl
#define dbg2(x1,x2) cout<<#x1<<" = "<<x1<<" "<<#x2<<" = "<<x2<<endl
#define dbg3(x1,x2,x3) cout<<#x1<<" = "<<x1<<" "<<#x2<<" = "<<x2<<" "<<#x3<<" = "<<x3<<endl
const int MAX_N = 100005;
priority_queue<pair<int,int> > q;
int ans[MAX_N],arr[MAX_N];
int num = 0;
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        num = 0;
        int n;
        scanf("%d",&n);
        for(int i = 1;i<=n;++i)
        {
            scanf("%d",&arr[i]);
            q.push(make_pair(arr[i],i));
        }
        int maxx = n;
        while(!q.empty())
        {
            pair<int,int> top = q.top();
            q.pop();
            if(top.second>maxx) continue;
            int xb = top.second;
            while(xb<=maxx)
            {
                ans[++num] = arr[xb];
                xb++;
            }
            maxx = top.second-1;
        }
        for(int i = 1;i<=n;++i)
        {
            i==n?printf("%d\n",ans[i]):printf("%d ",ans[i]);
        }
    }
    return 0;
}

C. Maximum width
定义完美字符串为T每个字符按顺序均属于S 两个字符间最长距离为所求值,一开始想到可能和长度有关 压位dp,但是不太好定义 于是定义出如下dp含义 dp[i][2] - dp[i][0] 代表T中第 i 个字符属于S最左能在什么位置 当然要比dp[i-1][0] 大,那么dp[i][1] 代表T中第 i 个字符属于S最右能在什么位置 当然要比 dp[i+1][1] 小 枚举点求答案

#include<cstdio>
#include<vector>
#include<cstring>
#include<cmath>
#include<iostream>
#include<queue>
using namespace std;
#define dbg(x) cout<<#x<<" = "<< (x)<< endl
#define dbg2(x1,x2) cout<<#x1<<" = "<<x1<<" "<<#x2<<" = "<<x2<<endl
#define dbg3(x1,x2,x3) cout<<#x1<<" = "<<x1<<" "<<#x2<<" = "<<x2<<" "<<#x3<<" = "<<x3<<endl
const int MAX_N = 200005;
priority_queue<pair<int,int> > q;
long long dp[MAX_N][2];
char str[MAX_N],str_[MAX_N];
vector<int> vt[35];
int main()
{
    int n,m,ans = 0;
    scanf("%d%d",&n,&m);
    scanf("%s",str+1);
    for(int i = 1;i<=n;++i)
    {
        vt[str[i]-'a'+1].push_back(i);
    }
    scanf("%s",str_+1);
    for(int i = 1;i<=m;++i)
    {
        dp[i][0] = 0x3f3f3f3f;
        dp[i][1] = 0;
    }
    dp[0][0] = 0,dp[m+1][1] = 0x3f3f3f3f;
    for(int i = 1;i<=m;++i)
    {
        int l = 0,r = vt[str_[i]-'a'+1].size()-1;
        while(l<=r)
        {
            int mid = (l+r)/2;
            if(vt[str_[i]-'a'+1][mid] > dp[i-1][0]) r = mid - 1;
            else l = mid + 1;
        }
        dp[i][0] = vt[str_[i]-'a'+1][l];
    }
    for(int i = m;i>=1;--i)
    {
        int l = 0,r = vt[str_[i]-'a'+1].size()-1;
        while(l<=r)
        {
            int mid = (l+r)/2;
            if(vt[str_[i]-'a'+1][mid] < dp[i+1][1]) l = mid+1;
            else r = mid - 1;
        }
        dp[i][1] = vt[str_[i]-'a'+1][r];
    }
    dp[m+1][1] = 0;
    for(int i = 1;i<=m;++i)
    {
        ans = max(1ll*ans,dp[i+1][1]-dp[i][0]);
    }
    printf("%d\n",ans);
    return 0;
}


D. Genius’s Gambit
当a=0或者b=1情况比较明显
手完出了 k<=a 与 k <=b-1的情况,写了个暴力归纳k<=a+b-2的情况 a+b-2可以将 k<=a 与 k<=b-1结合起来玩

#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
const int MAX_N = 200025;
char str[MAX_N];
int main()
{
    int a,b,k;
    scanf("%d%d%d",&a,&b,&k);
    if(a==0)
    {
        if(k==0)
        {
            printf("Yes\n");
            for(int i = 1;i<=b;++i) printf("1");printf("\n");
            for(int i = 1;i<=b;++i) printf("1");printf("\n");
        }
        else
        {
            printf("No\n");
        }
    }
    else if(b==1)
    {
        if(k==0)
        {
            printf("Yes\n");
            for(int i = 1;i<=b;++i) printf("1");for(int i = 1;i<=a;++i) printf("0");printf("\n");
            for(int i = 1;i<=b;++i) printf("1");for(int i = 1;i<=a;++i) printf("0");printf("\n");
        }
        else
        {
            printf("No\n");
        }
    }
    else
    {
        if(k<=a)
        {
            printf("Yes\n");
            for(int i = 1;i<=b-1;++i) printf("1");printf("1");for(int i = 1;i<=k;++i) printf("0");for(int i = 1;i<=a-k;++i) printf("0");printf("\n");
            for(int i = 1;i<=b-1;++i) printf("1");for(int i = 1;i<=k;++i) printf("0");printf("1");for(int i = 1;i<=a-k;++i) printf("0");printf("\n");
        }
        else if(k<=b-1)
        {
            printf("Yes\n");
            printf("1");for(int i = 1;i<=a-1;++i) printf("0");for(int i = 1;i<=k;++i) printf("1");printf("0");for(int i = k+2;i<=b;++i) printf("1");printf("\n");
            printf("1");for(int i = 1;i<=a-1;++i) printf("0");printf("0");for(int i = 1;i<=k;++i) printf("1");for(int i = k+2;i<=b;++i) printf("1");printf("\n");
        }
        else if(k<=a+b-2)
        {
            int len = 0;
            printf("Yes\n");
            for(int i = 1;i<=b;++i) printf("1");for(int i = 1;i<=a;++i) printf("0");printf("\n");
            for(int i = 1;i<=b-1;++i) str[++len] = '1';
            int xb = b;
            for(int i = 1;i<=a;++i) str[++len] = '0';
            str[++len] = '1';
            for(int i = 1;i<=k-a;++i) swap(str[xb],str[xb-1]),xb--;
            printf("%s\n",str+1);
        }
        else
        {
            printf("No\n");
        }
    }
    return 0;
}

E. Almost Fault-Tolerant Database
这题给你 n ∗ m n*m nm 个数,问你能否找到一行 m m m 个数,使得这 m m m 个数与每一行不同的数不超过 2 2 2
我们先考虑答案肯定和第一行不超过两个数(如果存在) 那么我们去拿第一行假设作为答案与其余行求 m a x d i f f maxdiff maxdiff 如果 m a x d i f f maxdiff maxdiff >= 5 5 5 肯定无解,因为你只能换两个位置 5 − 2 = 3 > = 2 5-2=3 >= 2 52=3>=2 那么当 m a x d i f f < = 2 maxdiff <= 2 maxdiff<=2 肯定输出第一行本身 如果 m a x d i f f = 4 maxdiff = 4 maxdiff=4 则交换其中两个元素, m a x d i f f = 3 maxdiff=3 maxdiff=3 比较麻烦,先交换一个,然后看是否满足情况 如果继续 m a x d i f f = 3 maxdiff = 3 maxdiff=3 则做组合交换 3 ∗ 3 3*3 33 情况,题解说 3 3 3 种情况 可能还是有不同的地方 另外代码也写的不够美观 感觉定义的太随意了 代码就越来越臃肿

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<stack>
#include<cstring>
#include<string>
#include<algorithm>
#include<set>
#include<map>
#include<vector>
using namespace std;

#define ll long long

const int MAX_N = 250025;
vector<int> vt[MAX_N];
int ans[MAX_N],cnt[MAX_N],maxx,xb,n,m,tmp[5],tmpLen,maxx_,xb_,tmp_[5],tmpLen_,maxx__,xb__;

void findDiff()
{
    maxx = -1;
    for(int i = 1;i<=n;++i) cnt[i] = 0;
    for(int i = 1;i<=n;++i)
    {
        for(int j = 1;j<=m;++j)
        {
            if(vt[i][j]!=ans[j]) cnt[i]++;
        }
        if(cnt[i]>maxx)
        {
            maxx = cnt[i];
            xb = i;
        }
    }
}

void findDiffOne()
{
    maxx_ = -1;
    for(int i = 1;i<=n;++i) cnt[i] = 0;
    for(int i = 1;i<=n;++i)
    {
        for(int j = 1;j<=m;++j)
        {
            if(vt[i][j]!=ans[j]) cnt[i]++;
        }
        if(cnt[i]>maxx_)
        {
            maxx_ = cnt[i];
            xb_ = i;
        }
    }
}

void findDiffTwo()
{
    maxx__ = -1;
    for(int i = 1;i<=n;++i) cnt[i] = 0;
    for(int i = 1;i<=n;++i)
    {
        for(int j = 1;j<=m;++j)
        {
            if(vt[i][j]!=ans[j]) cnt[i]++;
        }
        if(cnt[i]>maxx__)
        {
            maxx__ = cnt[i];
            xb__ = i;
        }
    }
}

void GOOD()
{
    printf("Yes\n");
    for(int i = 1;i<=m;++i)
    {
        i==m?printf("%d\n",ans[i]):printf("%d ",ans[i]);
    }
}

bool gao(int x,int y,int initXb)
{
    for(int i = 1;i<=m;++i) ans[i] = vt[1][i];
    ans[tmp[x]] = vt[initXb][tmp[x]];
    ans[tmp[y]] = vt[initXb][tmp[y]];
    findDiff();
    if(maxx<=2)
    {
        return true;
    }
    return false;
}

bool gaoOne(int x)
{
    ans[tmp_[x]] = vt[xb_][tmp_[x]];
    findDiffTwo();
    if(maxx__<=2)
    {
        return true;
    }
    return false;
}

int main()
{
    int x;
    scanf("%d%d",&n,&m);
    for(int i = 1;i<=n;++i) vt[i].push_back(-1);
    for(int i = 1;i<=n;++i)
    {
        for(int j = 1;j<=m;++j)
        {
            scanf("%d",&x);
            vt[i].push_back(x);
        }
    }
    for(int i = 1;i<=m;++i) ans[i] = vt[1][i];
    findDiff();
    if(maxx<=2)
    {
        GOOD();
    }
    else if(maxx>=5)
    {
        printf("No\n");
    }
    else if(maxx==3)
    {
        tmpLen = 0;
        for(int i = 1;i<=m;++i)
        {
            if(ans[i]!=vt[xb][i]) tmp[++tmpLen] = i;
        }
        for(int i = 1;i<=tmpLen;++i)
        {
            for(int j = 1;j<=m;++j) ans[j] = vt[1][j];
            ans[tmp[i]] = vt[xb][tmp[i]];
            findDiffOne();
            if(maxx_<=2)
            {
                GOOD();
                return 0;
            }
            if(maxx_>3)
            {
                continue;
            }
            tmpLen_ = 0;
            for(int j = 1;j<=m;++j) if(ans[j]!=vt[xb_][j]) tmp_[++tmpLen_] = j;
            for(int j = 1;j<=tmpLen_;++j)
            {
                int lastOne = ans[tmp_[j]];
                if(gaoOne(j))
                {
                    GOOD();
                    return 0;
                }
                else
                {
                    ans[tmp_[j]] = lastOne;
                }
            }
        }
        printf("No\n");

    }
    else
    {
        tmpLen = 0;
        for(int i = 1;i<=m;++i)
        {
            if(ans[i]!=vt[xb][i]) tmp[++tmpLen] = i;
        }
        int initXb = xb;
        if(gao(1,2,initXb)||gao(1,3,initXb)||gao(1,4,initXb)||gao(2,3,initXb)||gao(2,4,initXb)||gao(3,4,initXb))
        {
            GOOD();
        }
        else
        {
            printf("No\n");
        }
    }


    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值