sichuan2017 E. Longest Increasing Subsequence(LIS变形)

E. Longest Increasing Subsequence
Bobo learned how to compute Longest Increasing Subsequence (LIS) in O(n log n) in ICPCCamp.
For those who did not attend ICPCCamp as Bobo, recall LIS(a1, a2, … , an) is defined as f[1]2 ⊕ f[2]2 ⊕
· · · ⊕ f[n]
2 where ⊕ denotes the exclusive-or (XOR) and f is calculated as follows.
for i in [1, 2, …, n]
f[i] = 1
for j in [1, 2, …, i - 1]
if a[j] < a[i] then
f[i] = max(f[i], f[j] + 1)
Given sequence A = (a1, a2, … , an), Bobo would like to find LIS(B1), LIS(B2), … , LIS(Bn) where Bi
is the
sequence after removing the i-th element from A.
Input
The input contains zero or more test cases and is terminated by end-of-file. For each test case:
The first line contains an integer n. The second line contains n integers a1, a2, … , an.
• 2 ≤ n ≤ 5000
• 1 ≤ ai ≤ n
• The number of test cases does not exceed 10.
Output
For each case, output n integers which denote LIS(B1), LIS(B2), … , LIS(Bn).
Sample Input
5
2 5 3 1 4
Sample Output
5 13 0 8 0
题意:给你一个长度为n的序列,问当删除第i个数后,剩余数的LIS的平方的异或和是多少。
题解:首先o(nlogn)预处理出以ai为结尾的LIS的长度。
然后对于每次删除的数ai来说,位于ai前面的LIS的长度不变,后面的要么不变,要么-1。现在判断长度是否-1,假设ai后面存在一个数aj,如果aj前面存在一个数ak(!=ai),使得ak的LIS==aj的LIS-1并且ak < aj.则删除ai后,对aj的LIS没有影响。如果想对于任意的aj都尽量满足没有影响,则ak的值尽可能小。所以用s[]维护长度为i 的最小结尾。
代码:

#include<iostream>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<vector>
#include<queue>
#include<algorithm>
#include<map>
using namespace std;
typedef long long int ll;
typedef pair<int,int>pa;
const int N=1e5+10;
const int MOD=1e9+7;
const ll INF=1e18;
const int inf=1e4;
int read()
{
    int x=0;
    char ch = getchar();
    while('0'>ch||ch>'9')ch=getchar();
    while('0'<=ch&&ch<='9')
    {
        x=(x<<3)+(x<<1)+ch-'0';
        ch=getchar();
    }
    return x;
}
/************************************************************/
int n;
int a[N];
int dp[N];//记录以ai结尾的LIS的长度
int s[N];//记录长度为i的LIS的最小结尾
int f[N];//记录长度为i的LIS的结尾
void init()
{
    for(int i=1;i<=n;i++)
        scanf("%d",&a[i]);
        fill(dp,dp+N-1,inf);
    int cnt=0;
    f[++cnt]=a[1];
    dp[1]=cnt;
    for(int i=2;i<=n;i++)
    {
        if(a[i]>f[cnt])
        {
            f[++cnt]=a[i];
            dp[i]=cnt;
        }
        else
        {
            int pos=lower_bound(f+1,f+cnt,a[i])-f;
            f[pos]=a[i];
            dp[i]=pos;
        }
    }
}
int main()
{
    while(~scanf("%d",&n))
    {
        init();
        for(int i=1;i<=n;i++)
        {
            memset(s,0x3f3f3f3f,sizeof(s));
            s[0]=0;
            ll ans=0;
            for(int j=1;j<i;j++)
            {
                s[dp[j]]=min(s[dp[j]],a[j]);
                ans^=(ll)dp[j]*(ll)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^=(ll)dp[j]*(ll)dp[j];
                }
                else
                {
                    s[dp[j]-1]=min(s[dp[j]-1],a[j]);
                    ans^=(ll)(dp[j]-1)*(ll)(dp[j]-1);
                }
            }
            if(i!=1) printf(" ");
            printf("%lld",ans);
        }
        printf("\n");
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值