链接:http://codeforces.com/contest/873/

A题:

  贪心,把最大的k个数变成x即可。

B题:

  从左向右枚举右端点,维护balance的最长长度。任意一个子串可以看做两个前缀相减,对于已知当前右端点中1比0多多少个,只需要减去前面的某个前缀,在这个前缀中1比0也多这么多就可以了。所以开一个数组,维护1比0多i个的最左边的前缀的位置。

 C题:

  每一列相互独立单独处理,对于每一列贪心的选择去掉多少个1就可以了(显然只会从前往后逐次去掉)。

D题:

  首先注意到,k是偶数的时候是无解的,因为调用的次数必然是奇数。

  那么当k是奇数的时候,只要k不超过n个数能够调用的上界,就可以通过递归去构造。

  上界可以用递推得到。构造可以用递归得到。

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

const int maxn=100005;
int cnt[maxn];
int a[maxn];
int tot;

void print(int n,int k,int mi,int ma)
{
    if (k==1)
    {
        for (int i=0;i<n;i++) a[tot++]=mi+i;
    }
    else if (cnt[n]==k)
    {
        for (int i=n-1;i>=0;i--) a[tot++]=mi+i;
    }
    else
    {
        int l=0,r=n;
        int mid=(l+r)/2;
        if (cnt[mid-l]>=k-2)
        {
            int cou=mid-l;
            print(mid-l,k-2,ma-cou+1,ma);
            print(r-mid,1,mi,ma-cou);
        }
        else
        {
            int cou=mid-l;
            print(mid-l,cnt[mid-l],ma-cou+1,ma);
            print(r-mid,k-cnt[mid-l]-1,mi,ma-cou);
        }
    }
}

int main()
{
    int n,k;
    scanf("%d%d",&n,&k);
    cnt[1]=1;
    for (int i=2;i<=100000;i++)
    {
        int l=0,r=i;
        int mid=(l+r)/2;
        cnt[i]=cnt[mid-l]+cnt[r-mid]+1;
    }
    if (cnt[n]<k || k%2==0) printf("-1");
    else
    {
        print(n,k,1,n);
        for (int i=0;i<n;i++) printf("%d ",a[i]);
    }
    return 0;
}
problem D

相关文章:

  • 2021-05-28
  • 2021-09-14
  • 2021-10-11
  • 2022-02-05
  • 2021-08-20
  • 2022-12-23
  • 2022-12-23
  • 2021-11-26
猜你喜欢
  • 2021-10-17
  • 2021-05-25
  • 2021-11-17
  • 2021-12-11
  • 2022-01-20
  • 2021-06-28
  • 2021-10-30
相关资源
相似解决方案