CF#386(Div.2) 解题报告

来源:互联网 发布:轻而易举的软件多少钱 编辑:程序博客网 时间:2024/04/30 04:44

A

题意

给出a,b,c,取3个数满足0caa,0cbb,0ccc,ca:cb:cc=1:2:4,并且使ca,cb,cc的总和最大。如果无法满足,输出0.

数据范围

0a,b,c1000

题解

随便乱搞搞…

   #include<algorithm>   #include<iostream>   #include<cstring>   #include<cstdio>   #include<cmath>   #include<queue>   #include<ctime>   using namespace std;   int a,b,c,ans;   int main()   {    scanf("%d%d%d",&a,&b,&c);    for (int i=a;i>=1;--i)        if (i*2<=b&&i*4<=c) {ans=i+i*2+i*4;break;}    printf("%d\n",ans);   }

B

题意

一个长度为n的字符串的中间字符定义为s[n12+1],每次取出字符串的中间字符能拼成一个新的字符串。给出变换之后的字符串,求初始字符串。

数据范围

1n2000

题解

根据奇偶的不同加加减减
随便乱搞搞…

   #include<algorithm>   #include<iostream>   #include<cstring>   #include<cstdio>   #include<cmath>   #include<queue>   #include<ctime>   using namespace std;   #define N 5005   int n,now;   char s[N],ans[N];   int main()   {    scanf("%d\n",&n);gets(s+1);    now=(n-1)/2+1;    for (int i=1;i<=n;++i)    {        ans[now]=s[i];        if (n%2==0)        {            if (i%2) now+=i;            else now-=i;        }        else        {            if (i%2) now-=i;            else now+=i;        }    }    for (int i=1;i<=n;++i) putchar(ans[i]);    putchar('\n');   }

C

题意

数据范围

2s100,0x1,x2s,x1x2,1t1,t21000,1ps1,0d1

题解

很显然这道题只是比较人和车谁跑得快而已…
那么根据x1,x2,p的位置以及方向d分类讨论计算就可以了。

   #include<algorithm>   #include<iostream>   #include<cstring>   #include<cstdio>   #include<cmath>   #include<queue>   #include<ctime>   using namespace std;   int s,x1,x2,t1,t2,p,d,ans1,ans2,ans;   int main()   {    scanf("%d%d%d",&s,&x1,&x2);    scanf("%d%d",&t1,&t2);    scanf("%d%d",&p,&d);    if (x1==x2)    {        puts("0");        return 0;    }    if (x1<x2)    {        ans1=(x2-x1)*t2;        if (d==1)        {            if (p<=x1) ans2=(x2-p)*t1;            else ans2=(s-p+s+x2)*t1;        }        else ans2=(p+x2)*t1;    }    else    {        ans1=(x1-x2)*t2;        if (d==1)            ans2=(s-p+s-x2)*t1;        else        {            if (p>=x1) ans2=(p-x2)*t1;            else ans2=(p+s+s-x2)*t1;        }    }    ans=min(ans1,ans2);    printf("%d\n",ans);   }

D

题意

给出a个‘G’b个‘B’共n个字母,将他们排列,问是否存在一种方案使得这两个字母连续都不超过k个。

数据范围

1n,k105,0a,bn,a+b=n

题解

构造体吖
首先如果a=b特判
然后先将所有少的分散来放,再将多的塞在中间,都只塞一个,形成类似GBGBG这种形状,然后再把多余的多的塞到可以塞的位置,要保证合法。这样做可以防止之前放多了后来不够的情况。

#include<algorithm>#include<iostream>#include<cstring>#include<cstdio>#include<cmath>#include<queue>#include<ctime>using namespace std;#define N 100005int n,k,a,b;bool flag;int cnt[N];char A,B;int main(){    scanf("%d%d%d%d",&n,&k,&a,&b);    if (a==b)    {        for (int i=1;i<=n;++i)            if (i%2) putchar('G');            else putchar('B');        putchar('\n');        return 0;    }    if (a<b) swap(a,b),flag=1;    for (int i=1;i<=2*b+1;++i) cnt[i]=1;    a-=b+1;    for (int i=1;i<=2*b+1;i+=2)    {        if (a>=k-1)        {            cnt[i]+=k-1;            a-=k-1;        }        else        {            cnt[i]+=a;            a=0;        }        if (!a) break;    }    if (a)    {        puts("NO");        return 0;    }    if (!flag) A='G',B='B';    else A='B',B='G';    for (int i=1;i<=2*b+1;++i)    {        if (i%2)        {            while (cnt[i]--) putchar(A);        }        else        {            while (cnt[i]--) putchar(B);        }    }    putchar('\n');}

E

题意

给出一列n个数,问能否从1~m这些数中选出一些数替换掉这n个数中的若干数使得这n个数中奇数和偶数的个数相等并且没有重复出现的数。如果可以,输出最少替换个数和方案,否则-1.

数据范围

2n2105,1m109,1ai109

题解

其实这道题没什么难的,就是有点麻烦。
首先统计出来要换多少个数,然后分奇偶找就可以了。需要注意的是不需要替换的数尽量找大的,这样1~m的限制更容易被满足,是一个贪心的思想。

   #include<algorithm>   #include<iostream>   #include<cstring>   #include<cstdio>   #include<cmath>   #include<queue>   #include<ctime>   using namespace std;   #define N 200005   int n,m;   struct hp{int val,id;bool flag;}a[N];   int odd[N],even[N],cnt,cnto,cnte,anso[N],anse[N];   int cmpval(hp a,hp b)   {    return a.val>b.val;   }   int cmpid(hp a,hp b)   {    return a.id<b.id;   }   int main()   {    scanf("%d%d",&n,&m);    for (int i=1;i<=n;++i) scanf("%d",&a[i].val),a[i].id=i;    sort(a+1,a+n+1,cmpval);    a[0].val=0;odd[++odd[0]]=-1;even[++even[0]]=0;    for (int i=1;i<=n;++i)        if (a[i].val!=a[i-1].val)        {            if (a[i].val%2)            {                odd[++odd[0]]=a[i].val;                if (odd[0]-1<=n/2) a[i].flag=true;            }            else            {                even[++even[0]]=a[i].val;                if (even[0]-1<=n/2) a[i].flag=true;            }        }    if (odd[0]-1<=n/2) cnto=n/2-odd[0]+1;    if (even[0]-1<=n/2) cnte=n/2-even[0]+1;    cnt=cnto+cnte;    sort(odd+1,odd+odd[0]+1);    sort(even+1,even+even[0]+1);    for (int i=2;i<=odd[0];++i)    {        if (!cnto) break;        for (int j=odd[i-1]+2;j<odd[i];j+=2)        {            anso[++anso[0]]=j;            --cnto;            if (!cnto) break;        }    }    for (int i=odd[odd[0]]+2;i<=m;i+=2)    {        if (!cnto) break;        anso[++anso[0]]=i;        --cnto;    }    if (cnto)    {        puts("-1");        return 0;    }    for (int i=2;i<=even[0];++i)    {        if (!cnte) break;        for (int j=even[i-1]+2;j<even[i];j+=2)        {            anse[++anse[0]]=j;            --cnte;            if (!cnte) break;        }    }    for (int i=even[even[0]]+2;i<=m;i+=2)    {        if (!cnte) break;        anse[++anse[0]]=i;        --cnte;    }    if (cnte)    {        puts("-1");        return 0;    }    for (int i=1;i<=n;++i)        if (!a[i].flag)        {            if (anso[0]) a[i].val=anso[anso[0]--];            else a[i].val=anse[anse[0]--];        }    sort(a+1,a+n+1,cmpid);    printf("%d\n",cnt);    for (int i=1;i<=n;++i)        printf("%d%c",a[i].val," \n"[i==n]);   }

F

题意

n首歌,每个歌有一个喜悦值ai,以及时间ti。每首歌可以选择听一半或者听完。听一半的话时间定义为ti2。一共有k分钟,至多选择w首歌听一半,可以从任意一首歌开始听,但是不能跳歌,问获得的最大的喜悦值是多少。

数据范围

1wn2105,1k2109,1ai104,2ti104

题解

这道题可以用左右两个指针来解决,也就是单调地移动区间。
首先脑子正常的人都明白只要在w之内能听一半就听一半一定是更优的。如果区间长度小于或等于w的话一定是所有的歌都听一半,如果区间长度大于w的话那么应该选择这个区间里前w个大的来听一半,这样时间一定是更优的。
但是不能跳歌,也就是说如果一首歌无论如何都听不了的话后面的也就听不了了。所以无论何时端点移动的时候都必须满足要么区间里的所有歌都听一半,w可以有剩余,要么听区间里的前w大的歌。
这样每一次找最大值和最小值替换的时候就需要用到数据结构来维护,线段树就可以。

#include<algorithm>#include<iostream>#include<cstring>#include<cstdio>#include<cmath>#include<queue>#include<ctime>using namespace std;#define N 200005int n,w,k;int inf,l,r,sum,val,ans;int a[N],f[N],_f[N],h[N],_h[N];namespace Min{    int minn[N*4];    void update(int now)    {        if (_h[minn[now<<1]]<=_h[minn[now<<1|1]])            minn[now]=minn[now<<1];        else minn[now]=minn[now<<1|1];    }    void build(int now,int l,int r)    {        int mid=(l+r)>>1;        if (l==r)        {            minn[now]=l;            return;        }        build(now<<1,l,mid);        build(now<<1|1,mid+1,r);        update(now);    }    void change(int now,int l,int r,int x)    {        int mid=(l+r)>>1;        if (l==r)        {            minn[now]=x;            return;        }        if (x<=mid) change(now<<1,l,mid,x);        else change(now<<1|1,mid+1,r,x);        update(now);    }    int query(int now,int l,int r,int lrange,int rrange)    {        if (lrange>rrange) return 0;        int mid=(l+r)>>1,ans=0;        if (lrange<=l&&r<=rrange) return minn[now];        if (lrange<=mid)        {            int q=query(now<<1,l,mid,lrange,rrange);            if (_h[ans]>_h[q]) ans=q;        }        if (mid+1<=rrange)        {            int q=query(now<<1|1,mid+1,r,lrange,rrange);            if (_h[ans]>_h[q]) ans=q;        }        return ans;    }}namespace Max{    int maxn[N*4];    void update(int now)    {        if (_f[maxn[now<<1]]>=_f[maxn[now<<1|1]])            maxn[now]=maxn[now<<1];        else maxn[now]=maxn[now<<1|1];    }    void build(int now,int l,int r)    {        int mid=(l+r)>>1;        if (l==r)        {            maxn[now]=l;            return;        }        build(now<<1,l,mid);        build(now<<1|1,mid+1,r);        update(now);    }    void change(int now,int l,int r,int x)    {        int mid=(l+r)>>1;        if (l==r)        {            maxn[now]=x;            return;        }        if (x<=mid) change(now<<1,l,mid,x);        else change(now<<1|1,mid+1,r,x);        update(now);    }    int query(int now,int l,int r,int lrange,int rrange)    {        if (lrange>rrange) return 0;        int mid=(l+r)>>1,ans=0;        if (lrange<=l&&r<=rrange) return maxn[now];        if (lrange<=mid)        {            int q=query(now<<1,l,mid,lrange,rrange);            if (_f[ans]<_f[q]) ans=q;        }        if (mid+1<=rrange)        {            int q=query(now<<1|1,mid+1,r,lrange,rrange);            if (_f[ans]<_f[q]) ans=q;        }        return ans;    }}int main(){    scanf("%d%d%d",&n,&w,&k);    for (int i=1;i<=n;++i) scanf("%d",&a[i]);    for (int i=1;i<=n;++i)    {        scanf("%d",&f[i]);        _f[i]=f[i];        h[i]=(f[i]-1)/2+1;    }    memset(_h,127,sizeof(_h));inf=_h[0];    Max::build(1,1,n);    Min::build(1,1,n);    while (l<=n)    {        if (l<=r)        {            val-=a[l];            if (_h[l]!=inf)            {                sum-=h[l];                int loc=Max::query(1,1,n,l,r);                if (loc)                {                    sum-=f[loc]-h[loc];                    _f[loc]=0;_h[loc]=h[loc];                    Max::change(1,1,n,loc);Min::change(1,1,n,loc);                }                else ++w;            }            else sum-=f[l];        }        ++l;        r=max(r,l-1);        while (r<n)        {            if (w)            {                if (sum+h[r+1]<=k)                {                    sum+=h[r+1];                    _f[r+1]=0;_h[r+1]=h[r+1];                    Max::change(1,1,n,r+1);                    Min::change(1,1,n,r+1);                    --w;                    val+=a[++r];                }                else break;            }            else            {                int loc=Min::query(1,1,n,l,r);                if (loc&&f[loc]-h[loc]<f[r+1]-h[r+1]&&sum-h[loc]+f[loc]+h[r+1]<=k)                {                    sum+=f[loc]-h[loc];                    _f[loc]=f[loc];_h[loc]=inf;                    Max::change(1,1,n,loc);Min::change(1,1,n,loc);                    sum+=h[r+1];                    _f[r+1]=0;_h[r+1]=h[r+1];                    Max::change(1,1,n,r+1);Min::change(1,1,n,r+1);                    val+=a[++r];                }                else if (sum+f[r+1]<=k)                {                    sum+=f[r+1];                    val+=a[++r];                }                else break;            }        }        ans=max(ans,val);    }    printf("%d\n",ans);}

G

题意

构造一棵有n个节点,以1为根的树,满足共有t+1层,k个叶子节点,第i+1层有ai个节点。

数据范围

1n2105,1t,k<n,1ai<n

题解

怎么又是一道构造题…
首先如果这一层的节点数ai比下一层ai+1要多,那么这一层一定会有aiai+1个叶子节点。
最后一层的节点一定都是叶子节点。
那么我们可以计算出来最少的叶子节点有多少个,然后指定一些为一定为叶子节点。然后在剩余的点中建树,如果叶子节点不够的话就把儿子都往一个父亲上连,产生一些叶子节点,如果够了的话就一个儿子连一个父亲。

  #include<algorithm>  #include<iostream>  #include<cstring>  #include<cstdio>  #include<cmath>  #include<queue>  #include<ctime>  using namespace std;  #define N 200005  int n,t,k,must,last,now;  int a[N],b[N],s[N],f[N];  int main()  {    scanf("%d%d%d",&n,&t,&k);a[0]=s[0]=1;    for (int i=1;i<=t;++i)    {        scanf("%d",&a[i]);        s[i]=s[i-1]+a[i];        if (a[i]<a[i-1]) must+=a[i-1]-a[i],b[i-1]=a[i-1]-a[i];    }    must+=a[t];    if (s[t]!=n||must>k)    {        puts("-1");        return 0;    }    k-=must;    last=1,now=2;    for (int i=1;i<=t;++i)    {        if (k<=a[i-1]-1-b[i-1])        {            last+=k;            while (last<=s[i-1]-b[i-1]&&now<=s[i])            {                f[now]=last;                ++now,++last;            }            while (now<=s[i])            {                f[now]=last-1;                ++now;            }            k=0;        }        else        {            last+=a[i-1]-1-b[i-1];            while (last<=s[i-1]-b[i-1]&&now<=s[i])            {                f[now]=last;                ++now,++last;            }            while (now<=s[i])            {                f[now]=last-1;                ++now;            }            k-=a[i-1]-1-b[i-1];        }        last=s[i-1]+1;        now=s[i]+1;    }    if (k)    {        puts("-1");        return 0;    }    printf("%d\n",n);    for (int i=2;i<=n;++i) printf("%d %d\n",f[i],i);    return 0;  }
0 0
原创粉丝点击