**思路**
利用DP+二分查找依次找出最长递增子序列和最长递减子序列,取二者中较大值。
如果结果 ans>=n-k 那么这样的序列满足条件是一个魔法数组。
**代码**
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <algorithm>
using namespace std;
#define INT 0x7fffffff
int main()
{
//freopen("0.0.txt", "r", stdin);
int a[100010], n, k, top1, top2, T;
int arr[100010], a1[100010];
scanf("%d", &T);
while(T--)
{
memset(a, 0, sizeof(a));
memset(a1, 0, sizeof(a1));
scanf("%d%d",&n, &k);
int i;
top1 = 0;
top2 = 0;
a[0] = INT;
a1[0] = -INT;
for(i = 0; i < n; i++)
{
scanf("%d", &arr[i]);
}
for(i = 0; i < n; i++)
{
if(arr[i] < a[top1])
{
top1++;
a[top1] = arr[i];
}//发现递增数据进栈
else
{
int low = 1, high = top1;
while(low <= high)
{//二分查找
int mid = (low + high)/2;
if(arr[i] < a[mid])
low = mid + 1;
else
high = mid - 1;
}//while
a[low]=arr[i];
}//else
if(arr[i]>a1[top2])
{
top2++;
a1[top2]=arr[i];
}//发现递增数据进栈
else
{
int low=1,high=top2;
while(low<=high)
{//二分查找
int mid=(low+high)/2;
if(arr[i]>a1[mid])
low=mid+1;
else
high=mid-1;
}//while
a1[low]=arr[i];
}//else
}//for
int ans = top1 > top2 ? top1 : top2;
if(ans >= n-k) printf("A is a magic array.\n");
else printf("A is not a magic array.\n");
}//while
//system("pause");
return 0;
}
//其它模板
#include<cstdio>
#include<algorithm>
const int MAXN=200001;
int a[MAXN];
int d[MAXN];
int main()
{
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
d[1]=a[1];
int len=1;
for(int i=2;i<=n;i++)
{
if(a[i]>d[len])
d[++len]=a[i];
else
{
int j=std::lower_bound(d+1,d+len+1,a[i])-d;
d[j]=a[i];
}
}
printf("%d\n",len);
return 0;
}
int stack[10010];
int lis(int arr[],int n)
{
int i,top,mid,low,high;
top = 0;
stack[0] = -1;
for(i=0;i<n;i++)
{
if(arr[i]>stack[top])
stack[++top] = arr[i];
else
{
low = 1;
high = top;
while(low <= high)
{
mid = (low + high)/2;
if(arr[i] > stack[mid])
low = mid + 1;
else
high = mid - 1;
}
stack[low] = arr[i];
}
}
return top;
}