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