2017 四川省赛 Longest Increasing Subsequence 思维

时间:2021-06-08 23:21:25

PDF



题意:

给你N个数组成的序列,现在规定F【i】表示的是以a【i】结尾的最长上升子序列长度。

LIS(1)表示的是删除第一个数之后,F【i】的亦或和。

现在然你求LIS(1~N);



思路:

考虑我们如果删除第i个数,F【】的变化.

首先对于i前面的数,F【】都不会有影响.

那么对于i后面的数,他的F[j] 只会有两种情况,

1、如果存在一个数x,使其满足 F【x】=F[j]-1&&x!=i&&a[x]<a[j] 那么这个删除i后他的F仍为F[j]

2.如果不存在上面这样的数,那么F变为F【j】-1;



那么我们开一个数组s,s【len】表示当前长度最长上升子序列为len的,最后的那个元素最小是多少.那么这样

当我们要删除第i个元素的时候,就可以判断当前i的删除对j的整个上升序列是否有影响,然后维护一下s的最小值就好.

贪心的维护s的最小值,使得F,尽可能的还为F【j】



#include<bits/stdc++.h>
#define inf 0x3f3f3f3f
using namespace std;
typedef long long ll;
const int mod=1e9+7;
const int maxn=1e4+10;
int n;
int a[maxn];
int dp[maxn];
int s[maxn];

int main(){

while(~scanf("%d",&n))
{
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
}
for(int i=1;i<=n;i++)
{
dp[i]=1;
for(int j=1;j<=i-1;j++)
{
if(a[j]<a[i])
dp[i]=max(dp[i],dp[j]+1);
}
}
//memset(s,0,sizeof(s));
ll ans=0;
for(int i=1;i<=n;i++)
{
memset(s,inf,sizeof(s));
ans=0;
s[0]=0;
for(int j=1;j<=i-1;j++)
{
s[dp[j]]=min(s[dp[j]],a[j]);
ans^=(dp[j]*dp[j]);
}
for(int j=i+1;j<=n;j++)
{
if(a[j]>s[dp[j]-1])
{
s[dp[j]]=min(s[dp[j]],a[j]);
ans^=(dp[j]*dp[j]);
}
else
{
s[dp[j]-1]=min(s[dp[j]-1],a[j]);
ans^=((dp[j]-1)*(dp[j]-1));
}
}
if(i!=1)printf(" ");
printf("%lld",ans);
}
puts("");
}
return 0;
}