Genius ACM

题解:

发现匹配一定会选最大和最小匹配,确定左右端点之后nlogn排序后算

比较容易想到二分 最坏情况每次1个 $n^2*(logn)^2$

没错暴力的最差复杂度是$n^2*logn$的

发现长度与次数相关

二分改成倍增 $n(logn)^2$

然后大概常数好就过了吧

倍增的时候我们可以把排序看成一段有序的+一段无序的

可以把无序的先排序再和有序的归并

时间复杂度nlogn

代码:

#include <bits/stdc++.h>
using namespace std;
#define rint register int
#define IL inline
#define rep(i,h,t) for (rint i=h;i<=t;i++)
#define dep(i,t,h) for (rint i=t;i>=h;i--)
#define ll long long
char ss[<<],*A=ss,*B=ss;
IL char gc()
{
return A==B&&(B=(A=ss)+fread(ss,,<<,stdin),A==B)?EOF:*A++;
}
template<class T>void read(T &x)
{
rint f=,c; while (c=gc(),c<||c>) if (c=='-') f=-; x=(c^);
while (c=gc(),c>&&c<) x=(x<<)+(x<<)+(c^); x*=f;
}
const int N=6e5;
int a[N],b[N],n,m,c[N],d[N],e[N],len;
ll k;
IL bool check(rint x,rint y)
{
rint len=y-x+;
rep(i,x,y) b[i-x+]=a[i];
sort(b+,b+len+);
rint tmp=len/;
ll ans=;
rep(i,,m)
{
if (i>tmp) break;
ans+=1ll*(b[i]-b[len-i+])*(b[i]-b[len-i+]);
}
if (ans<=k) return(); else return();
}
IL bool check(rint x,rint y,rint h2,rint t2)
{
rint len2=t2-h2+;
rep(i,h2,t2) c[i-h2+]=a[i];
sort(c+,c+len2+);
int h1=,t1=len; h2=,t2=len2;
int cnt=;
while (h2<=t2&&h1<=t1)
{
if (b[h1]<c[h2]) d[++cnt]=b[h1],h1++;
else d[++cnt]=c[h2],h2++;
}
while (h1<=t1) d[++cnt]=b[h1],h1++;
while (h2<=t2) d[++cnt]=c[h2],h2++;
rep(i,,len) e[i]=b[i];
rep(i,,cnt) b[i]=d[i];
rint tmp2=len; len=cnt;
rint tmp=len/;
ll ans=;
rep(i,,m)
{
if (i>tmp) break;
ans+=1ll*(b[i]-b[len-i+])*(b[i]-b[len-i+]);
}
if (ans<=k) return(); else
{
len=tmp2;
rep(i,,len) b[i]=e[i];
return();
}
}
IL int js(register int x)
{
register int y=x;
register int i=;
register int lst=x-;
while (i>=)
{
for (i=;i<=;i++)
{
if (!check(y,x+(<<i)-,lst+,x+(<<i)-)) break;
lst=x+(<<i)-;
}
i--;
x=x+(<<i)-;
i--;
if (x>n) break;
}
return x;
}
int main()
{
freopen("geniusacm.in","r",stdin);
freopen("geniusacm.out","w",stdout);
int T;
read(T);
rep(tt,,T)
{
read(n); read(m); read(k);
rep(i,,n) read(a[i]);
int now=,cnt=;
while (now<=n)
{
len=;
now=js(now)+;
cnt++;
}
cout<<cnt<<endl;
}
return ;
}
上一篇:Java序列化的几种方式以及序列化的作用


下一篇:D/A转换器