Codeforces Round #547 (Div. 3)[a,b,c,d,e,f], Codeforces Round #598 (Div. 3)

链接:Codeforces Round #547 (Div. 3)

A. Game 23

题意:

给a和b,a可以选择a*2或者a*3来变成b,问最少几步变成b,变不出输出-1

先判断b%a能否=0,c=b/a,c变成1的最小步数

ac:

#include<bits/stdc++.h>
#define IOS std::ios::sync_with_stdio(false);
#define pb push_back
#define ll long long
#define mod 1000000007
#define per(i,a,b) for(int i=a;i<b;i++)
#define rep(i,a,b) for(int i=a;i>=b;i--)
using namespace std;


int main()
{
    int a,b;
    cin>>a>>b;
    int c=b/a;
    int d=b%a;
    if(d!=0||b<a)
    {
        printf("-1\n");
        return 0;
    }
    int cnt=0;
    while(c%2==0)
    {
        c=c/2;
        cnt++;
    }
    while(c%3==0)
    {
        c=c/3;
        cnt++;
    }
    if(c!=1)
        printf("-1\n");
    else printf("%d\n",cnt);
    return 0;
}

B. Maximal Continuous Rest

题意:

给一天每小时的休息情况,问最多休息时间,必休息一次

解析:

开两倍数组遍历

ac:

#include<bits/stdc++.h>
#define MAXN 400005
using namespace std;

int a[MAXN]={0};

int main()
{
    int n;
    scanf("%d",&n);
    for(int i=0;i<n;i++)
    {
        scanf("%d",&a[i]);
        a[n+i]=a[i];
    }
    int maxs=0;
    for(int i=0;i<2*n;i++)
    {
        if(a[i]==0) continue;
        a[i]=a[i-1]+a[i];
        maxs=max(maxs,a[i]);
    }
    printf("%d\n",maxs);
    return 0;
}

C. Polycarp Restores Permutation

题意:

qi=pi+1−pi,给(1~n-1)的qi,求(1~n)的pi

解析:

给pn赋值400005,从后往前推

找(1~n)里pi最小的,每个pi减去(mins-1),就一定有个pi等于1

遍历pi,判断是否超过n或者重复

ac:

#include<bits/stdc++.h>
#define ll long long
#define MAXN 500005
using namespace std;

int a[MAXN];
int b[MAXN];
map<ll,int> vis;

int main()
{
    int n;
    scanf("%d",&n);
    for(int i=1;i<n;i++)
        scanf("%d",&a[i]);
    int c=400005;
    b[n]=c;
    int maxs=b[n];
    for(int i=n-1;i>=1;i--)
    {
        b[i]=b[i+1]-a[i];
        maxs=min(b[i],maxs);
    }
    maxs--;
    for(int i=1;i<=n;i++)
    {
        b[i]=b[i]-maxs;
        if(vis[b[i]]==1||(b[i]>n))
        {
            printf("-1\n");
            return 0;
        }
        vis[b[i]]=1;
    }
    for(int i=1;i<n;i++)
        printf("%d ",b[i]);
    printf("%d\n",b[n]);
    return 0;
}

另外一种差不多的写法

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

typedef long long LL;
const int Max_n=200005;
int a[Max_n],b[Max_n];
set<int> st;

int main()
{
    int n;
    scanf("%d",&n);
    int mmin=Max_n;
    int mmax=-Max_n;
    for(int i=2;i<=n;i++)
    {
        scanf("%d",&a[i]);
        b[i]=b[i-1]+a[i];
    }
    for(int i=1;i<=n;i++)
    {
        st.insert(b[i]);
        mins=min(mins,b[i]);
        maxs=max(maxs,b[i]);
    }
    int len=st.size();
    if(len!=n||maxs-mins!=n-1)//st自动去重复,如果有重复,len!=n
    {                         //mmax-min!=n-1,会有pi超过n
        printf("-1\n");
        return 0;
    }
    for(int i=1;i<=n;i++)
        printf("%d%c",b[i]-mins+1,i==n?'\n':' ');
    return 0;
}

D. Colored Boots

题意:

给定a串b串,里面有?,?可以变任何字母

求a串和b串字母个数相同的最多数目

解析:

直接模拟就可以了,先比a~z,在a~z和?匹配,如果?有多,?和?匹配

ac:

#include<bits/stdc++.h>
#define pb push_back
#define MAXN 500000
using namespace std;

char str[MAXN];
char ctr[MAXN];
queue<int> vca[100],vcb[100];

int aa[MAXN],bb[MAXN];

int main()
{
    int cnt=0;
    int n;
    scanf("%d",&n);
    scanf("%s",str+1);
    scanf("%s",ctr+1);

    for(int i=1;i<=n;i++)
    {
        if(str[i]=='?')
            vca[30].push(i);
        else  vca[str[i]-'a'+1].push(i);
        if(ctr[i]=='?')
            vcb[30].push(i);
        else  vcb[ctr[i]-'a'+1].push(i);
    }

    for(int i=1;i<=26;i++)
    {
        while(vca[i].size()>0&&vcb[i].size()>0)
        {
            aa[cnt]=vca[i].front();
            bb[cnt]=vcb[i].front();
            cnt++;
            vca[i].pop();
            vcb[i].pop();
        }
    }

    if(vca[30].size()>0)
    {
        for(int i=1;i<=26;i++)
        {
            while(vcb[i].size()>0&&vca[30].size()>0)
            {
                aa[cnt]=vca[30].front();
                bb[cnt]=vcb[i].front();
                cnt++;
                vcb[i].pop();
                vca[30].pop();
            }
        }
    }

    if(vcb[30].size()>0)
    {
        for(int i=1;i<=26;i++)
        {
            while(vca[i].size()>0&&vcb[30].size()>0)
            {
                aa[cnt]=vca[i].front();
                bb[cnt]=vcb[30].front();
                cnt++;
                vca[i].pop();
                vcb[30].pop();
            }
        }
    }

    while(vca[30].size()>0&&vcb[30].size()>0)
    {
        aa[cnt]=vca[30].front();
        bb[cnt]=vcb[30].front();
        cnt++;
        vca[30].pop();
        vcb[30].pop();
    }

    printf("%d\n",cnt);
    for(int i=0;i<cnt;i++)
        printf("%d %d\n",aa[i],bb[i]);
    return 0;
}

E. Superhero Battle

给定怪的血量

英雄每回合的伤害,伤害可能为正(加血),回合是循环的

问最少几回合打死野怪,打不死输出-1

解析:

前缀和+二分

前缀和求sum[i](1~k),求里面最小的

二分找最小的q,n-q*sum[k]+mins<=0

要注意q的范围,这题数据很严,直接赋r过大会造成q*sum[k]+mins溢出ll的负下限,我们先求r的不溢出上限

解析:

#include<bits/stdc++.h>
#define MAXN 3000005
#define ll long long
using namespace std;

ll a[MAXN];
ll sum[MAXN];

int main()
{
    ll n,k;
    scanf("%lld%lld",&n,&k);
    for(ll i=1;i<=k;i++)
        scanf("%lld",&a[i]);
    sum[1]=a[1];
    for(ll i=2;i<=k;i++)
        sum[i]=sum[i-1]+a[i];
    ll mins=999999999999999;
    for(ll i=1;i<=k;i++)
    {
        mins=min(mins,sum[i]);
        if(n+sum[i]<=0)
        {
            printf("%lld\n",i);
            return 0;
        }
    }
    if(sum[k]>=0)
    {
        printf("-1\n");
    }
    else{
        ll l=1,r=(9e18+mins)/(-1*sum[k]);//防止sum[k]*mid+mins越界
        ll q=r;
        while(l<=r)
        {
            ll mid=(l+r)/2;
            if(n+sum[k]*mid+mins<=0)
            {
                r=mid-1;
                q=min(q,mid);
            }
            else{
                l=mid+1;
            }
        }
        n=n+q*sum[k];
        for(ll i=1;i<=k;i++)
        {
            if(n+sum[i]<=0)
            {
                printf("%lld\n",q*k+i);
                break;
            }
        }
    }
    return 0;
}

F2. Same Sum Blocks (Easy)

题意

给一个数组,

求一些不相交的区间,每个区间的和为k,求区间的最大数目

解析:

先求前缀和

两层循环遍历区间,将相同区间和的区间装入vector中

最后遍历每一个区间,贪心求最多区间数目

ac:

#include<bits/stdc++.h>
#define ll long long
#define MAXN 3000005
using namespace std;

struct node
{
    int x,y;
    bool friend operator <(node a,node b)
    {
        if(a.y==b.y)
            return a.x<b.x;
        else return a.y<b.y;
    }
};

int a[MAXN];
int sum[MAXN];
map<ll,int> mp;
vector<node> vc[MAXN];
int cnt;

int main()
{
    //freopen("E:/in.txt","r",stdin);
    cnt=1;
    int n;
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&a[i]);
        sum[i]=sum[i-1]+a[i];
    }
    for(int i=1;i<=n;i++)
    {
        for(int j=i;j<=n;j++)
        {
            int cc=sum[j]-sum[i-1];
            if(mp[cc]==0)
            {
                mp[cc]=cnt;
                vc[cnt].push_back({i,j});
                cnt++;
            }
            else{
                vc[mp[cc]].push_back({i,j});
            }
        }
    }

    int maxs=0,qc,ans=0;
    for(int i=1;i<cnt;i++)
    {
        int len=vc[i].size();
        if(len<ans)
            continue;
        int r=0,sum=0;
        sort(vc[i].begin(),vc[i].end());
        for(int j=0;j<vc[i].size();j++)
        {
            if(vc[i][j].x>r)
            {
                r=vc[i][j].y;
                sum++;
            }
        }
        if(sum>ans)
        {
            ans=sum;
            qc=i;
        }
    }

    printf("%d\n",ans);
    int r=0;
    for(int i=0;i<vc[qc].size();i++)
    {
        if(vc[qc][i].x>r)
        {
            printf("%d %d\n",vc[qc][i].x,vc[qc][i].y);
            r=vc[qc][i].y;
        }
    }
    return 0;
}

https://codeforces.com/contest/1256

题意:

B. Minimize the Permutation

题意:

给定一个数组,让你选择两组相邻元素交换,(i,i+1),每个位置只能选择一次

解析:

贪心,从小到大选择,并标记

ac:

#include<bits/stdc++.h>
#define MAXN 105
using namespace std;
int a[MAXN];
int vis[MAXN];
int c[MAXN];

int main()
{
    int n,t;
    scanf("%d",&t);
    while(t--)
    {
        memset(c,0,sizeof(c));
        memset(vis,0,sizeof(vis));
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
            scanf("%d",&a[i]),vis[a[i]]=i;
        for(int i=1;i<=n;i++)
        {
            int sign=1;
            while(sign)
            {
                int x=vis[i];//小的位置
                int y=vis[i]-1;
                if(a[x]<a[y]&&y>0&&c[y]==0){
                    swap(vis[a[x]],vis[a[y]]);
                    swap(a[x],a[y]);
                    c[y]=1;
                }
                else{
                    sign=0;
                }
            }
        }
        for(int i=1;i<=n;i++)
            printf("%d ",a[i]);
        printf("\n");
    }
    return 0;
}

C. Platforms Jumping

题意:

一条长为n的河,你在0位置,要到n+1位置,河上有一些木板

木板的顺序不能改变,你可以改变木板的位置

你在x位置,你可以一次移动到(x+1,x+d),问你能否从0到n+1

解析:

如果木板的长度和>n,呢么就必然失败

贪心,尽可能将木板往右放,后面的木板可能连在一次

ac:

#include<bits/stdc++.h>
#define MAXN 2005
#define ll long long
using namespace std;
int a[MAXN];
int sum[MAXN];
int c[MAXN];

int main()
{
    int n,m,d;
    scanf("%d%d%d",&n,&m,&d);
    for(int i=1;i<=m;i++)
        scanf("%d",&a[i]);
    for(int i=m;i>=1;i--)
        sum[i]=sum[i+1]+a[i];
    int sign=0,st=0;
    for(int i=1;i<=m;i++)
    {
        int cc=n-(st+sum[i]);//在将(i,n)木板全部在一起不超过n的情况下,最远跳过的水域距离
        cc=min(cc,d-1);
        st=st+1+cc;
        for(int j=st;j<=st+a[i]-1;j++)
            c[j]=i;
        st=st+a[i]-1;
    }
    if(st+d<=n||st>n)
    {
        printf("NO\n");
        return 0;
    }
    printf("YES\n");
    for(int i=1;i<=n;i++)
        printf("%d ",c[i]);
    printf("\n");
    return 0;
}

https://codeforces.com/contest/1256/problem/D

题意:

给定一个二进制字符串,你右k次机会,每次可以选择两个相邻字符交换他们,问k次后最后字典序最小的情况

解析:

直接贪心

#include<bits/stdc++.h>
#define MAXN 1000005
#define ll long long
using namespace std;

char s[MAXN];
int main()
{
    ll t,n,k;
    scanf("%lld",&t);
    while(t--)
    {
        scanf("%lld%lld",&n,&k);
        scanf("%s",s+1);
        ll g=1,sign=0,vis=0;
        for(ll i=1;i<=n&&k;i++)
        {
            if(s[i]=='0'){
                int d=min(k,i-g);
                k=k-d;
                sign=g+(i-g)-d;
                if(d==i-g)
                    g++;
            }
            vis=i;
        }
        //g为直接0的情况,sign为最后移动移动的0的位置,vis为最后变换的位置
        for(int i=1;i<=n;i++)
        {
            if(i<g||i==sign){
                printf("0");
            }
            else if(i<=vis){
                printf("1");
            }
            else{
                printf("%c",s[i]);
            }
        }
        printf("\n");
    }
    return 0;
}

 

E.题意:

给定一个数组,将数组分未若干份,每份至少有3个元素,每组的权值未其中极大-极小

怎么分使得所以组的权值和最小?输出分组

解析:

如果元素>=6,呢么显然将他们分成至少2组.

递推式:i-j>=0&&dp[i]>dp[i-j]+ee[i].v-ee[i-j+1].v

更新的时候,顺便记录路径

ac:

#include<bits/stdc++.h>
#define MAXN 200005
#define ll long long
using namespace std;
struct node
{
    int v,id;
    friend bool operator <(node a,node b)
    {
        return a.v<b.v;
    }
}ee[MAXN];
int dp[MAXN];
int pre[MAXN];
int ans[MAXN];
 
int main()
{
    int n;
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
        scanf("%d",&ee[i].v),ee[i].id=i;
    sort(ee+1,ee+n+1);
    memset(dp,0x3f3f3f,sizeof(dp));
    dp[0]=0;
    pre[0]=0;
    for(int i=3;i<=n;i++)
    {
        for(int j=3;j<=5;j++)
        {
            if(i-j>=0&&dp[i]>dp[i-j]+ee[i].v-ee[i-j+1].v){
                dp[i]=dp[i-j]+ee[i].v-ee[i-j+1].v;
                pre[i]=i-j;
            }
        }
    }
    int tot=0;
    for(int i=n;i>=1;i=pre[i])
    {
        ++tot;
        for(int j=i;j>pre[i];j--)
            ans[ee[j].id]=tot;
    }
    printf("%d %d\n",dp[n],tot);
    for(int i=1;i<n;i++)
        printf("%d ",ans[i]);
    printf("%d\n",ans[n]);
    return 0;
}

https://codeforces.com/contest/1256/problem/F

题意:

给定两个字符串s和t,你可以选择一段长度为len的s的子串反转,将长度为len的t的一种子串反转

如果最后s和t能相同,输出YES

解析:

因为交换次数无限制,所以对于len>2的情况,都可能通过若干次len=2的操作实现,我们仅考虑len=2的情况

1.如果字符串字母构成不能,必定失败

2.如果字符串中有一个字符个数>1,呢么将两个相同的移动到两端之一,然后一定可以通过若干次操作将s和t相同

3.如果字符串中没有字符个数>1,这种字符串最多长为26,然后我们可能通过冒泡排序,将他们按字典序方式排序

如果排序次数相同,则YES,通过计算逆序数的方法原理是相同的

ac:

#include<bits/stdc++.h>
#define MAXN 200005
using namespace std;

char s[MAXN];
char c[MAXN];
int aa[30],bb[30];
int main()
{
    int t,n;
    scanf("%d",&t);
    while(t--)
    {
        memset(aa,0,sizeof(aa));
        memset(bb,0,sizeof(bb));
        scanf("%d",&n);
        scanf("%s",s+1);
        scanf("%s",c+1);
        for(int i=1;i<=n;i++){
            aa[s[i]-'a']++;
            bb[c[i]-'a']++;
        }
        int sign=0,maxs=0;
        for(int i=0;i<26;i++){
            if(aa[i]!=bb[i]){
                sign=1;
            }
            maxs=max(maxs,aa[i]);
        }
        if(sign==1){//构成不同
            printf("NO\n");
        }
        else{
            if(maxs>1){//有重复字母
                printf("YES\n");
            }
            else{
                int va=0,vb=0;
                for(int i=1;i<=n;i++)
                {
                    for(int j=i+1;j<=n;j++)
                    {
                        if(s[j]>s[i]){
                            va++;
                            swap(s[j],s[i]);
                        }
                        if(c[j]>c[i]){
                            vb++;
                            swap(c[j],c[i]);
                        }
                    }
                }
                if(va%2==vb%2){//直接计算逆序数,判断逆序数相同
                    printf("YES\n");
                }
                else
                    printf("NO\n");
            }
        }
    }
    return 0;
}

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值