[codeforces/edu30]总结(E)

链接: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

E题:

  待补。

F题:

  reverse一下,不能以某个位置结尾变成不能以某个位置开头。然后做一次后缀数组,得到height数组。要想让|a|·f(a)最大,那么a必然是某一个后缀。如果一个后缀的开头不是bad position,直接把这个后缀的长度更新答案。那么对于要匹配两个及以上后缀的,这个结果基本上跟height数组形成的柱状图有关,类似于用单调栈维护一下以每个位置为扩展的最大面积即可。

posted @ 2017-10-31 17:02  ACMsong  阅读(191)  评论(0编辑  收藏  举报