发现做法和别人不同,那就写个题解 (另外本题是神大抄的GCJ题目,数据出的很弱,可以去gcj测一下Google Code Jam)
(约定F(l,r)为区间[l,r]在不交换的情况下满足题意的K)
试想不能交换,那么我们可以O(n)求出F(1,n)。如果能交换一次,很显然,只能是
[l1,r1]
和
[l2,r2]
,并且满足
Li≤l1≤r1<l2≤r2≤Ri,1≤i≤K
,因为这样才能对答案作出贡献。定义
f(i)
为第
i
段区间能交换一次的答案,这样将问题转换为求出
#include <cstdio>
#include <cmath>
#include <iostream>
using namespace std;
const int maxn = 5010;
int n;
int st[maxn][32];
int lg2[maxn];
struct node
{
int l,r;
}stk[maxn];
int a[maxn];
int p[maxn];
int f[maxn],s[maxn];
inline int max(int x,int y)
{
return x > y ? x : y;
}
inline int min(int x,int y)
{
return x < y ? x : y;
}
void init()
{
lg2[1] = 0;
for(int i = 2; i <= n; i++)
lg2[i] = lg2[i-1] + (1 << (lg2[i-1] + 1) == i);
int k = lg2[n] + 1;
for(int i = 1; i <= n; i++)
st[i][0] = a[i];
for(int j = 1; j < k; j++)
for(int i = 1; i <= n; i++)
if(i + (1 << j) <= n + 1)
st[i][j] = max(st[i][j-1],st[i+(1 << (j-1))][j-1]);
}
int q(int l,int r)
{
int k = lg2[r - l + 1];
return max(st[l][k],st[r - (1 << k) + 1][k]);
}
int L[maxn],cl;
int R[maxn],cr;
int work(int l,int r,int L)
{
int res = 0;
int j;
for(int i = l; i <= r; i++)
{
j = L + i - l;
if(a[i] != j)
{
int k = p[j];
int qq;
while(1)
{
qq = q(i,k);
if(qq - j == k - i)
break;
k = qq - j + i;
}
i = qq - j + i;
}
res++;
}
return res;
}
int calc(int l,int r)
{
cl = cr = 0;
int minn = 1e9;
for(int i = l; i <= r; i++)
{
minn = min(a[i],minn);
if(r - minn == i - l)
L[++cl] = i;
}
int maxx = 0;
for(int i = r; i >= l; i--)
{
maxx = max(a[i],maxx);
if(maxx - l == r - i)
R[++cr] = i;
}
int res = 0;
for(int i = 1; i <= cl; i++)
{
for(int j = 1; j <= cr; j++)
{
if(L[i] >= R[j])
break;
int mid = work(L[i]+1,R[j]-1,r - R[j] + l + 1);
res = max(res,mid+1);
}
}
return res;
}
int main()
{
int T;
cin >> T;
for(int cas = 1; cas <= T; cas++)
{
printf("Case #%d: ",cas);
int cnt = 0;
int ans = 0;
int ppp;
scanf("%d",&n);
for(int i = 1; i <= n; i++)
{
scanf("%d",&a[i]);
f[i] = 0;
p[a[i]] = i;
}
init();
for(int i = 1; i <= n; i++)
{
int l = i;
if(a[i] != i)
{
int j = p[i];
while(1)
{
int qq = q(l,j);
if(qq == j)
break;
j = qq;
}
i = j;
}
stk[++cnt].l = l;
stk[cnt].r = i;
}
for(int i = 1; i <= cnt; i++)
{
if(stk[i].l == stk[i].r)
continue;
ans = max(ans,calc(stk[i].l,stk[i].r));
}
printf("%d\n",cnt+ans);
}
return 0;
}