ZSTU2019校赛 Problem D Lis(线性基dp)

我的做题思路参考的是这位大佬(代码就把他的抄了一遍

https://blog.csdn.net/kzn2683331518/article/details/88768657

题面

令LIS(S)为序列S的最长递增子序列的长度
给你n个非负整数,a[0],a[1],...,a[n-1],你可以对这个数组进行零次或多次操作,每次操作选择一个i(0<=i<=n-2),将a[i+1]变成(a[i+1] xor a[i])
你的任务是使得LIS(a)越大越好,输出LIS(a)的最大值

解题思路:

一步步来

1.  首先知道a^b^b = a 这个性质,并且一个数可以无限次异或前一位。

那么举个例子

a1 a2 a3 a4,请问a4可以得到哪几种异或的结果?

①:a2=a2^a1  -->  a3=a3^(a2^a1)  -->  a4=a4^(a3^a2^a1),这是第一种

②:a3=a3^a2  -->  a4=a4^(a3^a2),这是第二种

③:a4 = a4^a3,这是第三种

④ :在①的基础上a2 =(a2^a1)^a1=a2

a3  = (a3^a2^a1)^a2=a3^a1

a4 = (a4^a3^a2^a1)^(a3^a1) = a4^a2,这是第四种

⑤:对前面三项经过多次操作后,还可以得到a4^a1, a4^a1^a2, a4^a1^a3, a4^a2^a3...

于是归纳出结论:对于a[i],可以xjb乱异或前面的a[j]   (j<i)

2.  构造线性基数组

还是举个例子吧:

给你五个数:

5 7 8 9 12

转化为二进制:

101  111  1000  1001  1100

亲,跟着我这么做:

首先构造一个lb[i][j]二维数组,表示是a[i]第j位上的线性基

现在我们假设求a[6]的线性基:

①先分析一下:

我们知道,暴力求出a[6]有多少种异或的方法并得到最小值需要2的五次方次(也就是2的(i-1)次方)计算

而利用线性基求固定63次运算(n很大的时候就省时间了)

63怎么得来的(long long型正数最大二进制下63位)

②开始构造a[6]的线性基,构造完再讲一下原理:

先扔进来101,从高到低遍历,第三位是1,判断lb[6][3]是否被赋值过(显然没有,还是初始化状态)

于是lb[6][3]=101(5),oj8k,直接return。

再扔进来111,再遍历,第三位是1,但lb[6][3]被赋值过,那怎么办?把111^lb[6][3],变成了010,

再判断第二位是1,lb[6][2]没有被赋值,于是lb[6][2]=010(2),oj8k.

然后打字好累长话短说,lb[6][4]=8

lb[6][1] = 1

最后的1100变成0,最后没有进入lb[6]的线性基

最后,看构造出来的lb[6]结果:

0101

0010

1000

0001

因为前五个数没有超过15的,所以只要四位就够了,这样四个每个都有一个1在各自位子上的数一定可以表示出这四个数异或出来的所有结果,而a[6]异或最大值只要将他的线性基从高到低遍历,如果当前线性基使得结果增大,那么就异或一下。

(这里具体我就说不清了,根据a^b^b=a这个性质应该可以证明)

3.构造dp数组:

前面求得了线性基,最终目的是修改a[i]的值,使其比a[i-1]大的同时尽可能小。

dp[i][j]表示前i位长度为j的lis最小后缀(注意LIS不必是连续的一串,中间可以断一下)

dp[i][j] = min (dp[i-1][j],计算得来的dp[i][j]);

4.关于代码里求比上一项大的最小值的那一坨代码(getminmax)的解释

看懂了代码其他部分再来看吧

先预设x为最大值,

if(x<g)滚,没有,最大的都不是
else {
    x异或当前位,判断是否比g大,
       大就判断和之前x谁大
       小就对后面的基搞来搞去,搞出后面的基可以异或出的最大的数
       如果比g大,那么此时最小的x就变成tmp
      要问为什么?(因为我来了)        x = same 1 xxxx >g
                                                这个  tmp = same 0 yyyy > g
}

 

代码:(这个1要longlong 是真的挺坑的,我打赌以后自己还会错)

#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
#define INF 0x3f3f3f3f3f3f3f3f
using namespace std;

const int N = 105;

ll lb[N][65],dp[N][N],a[N];

void get_lb(int i,ll x)
{
    for (int j = 62;j>=0;j--){
        if ((x>>j)&1){
        //if (((ll)1<<j)&x){//或者这样,但是记得longlong
            if (!lb[i][j+1]){
                lb[i][j+1] = x;
                return ;
            }
            else x = x^lb[i][j+1];
        }
    }
}

ll getmin(int i,ll x)
{
    ll ans = x;
    for (int j=63;j>=1 && ans;j--){
        ans = min(ans,ans^lb[i][j]);
    }
    return ans;
}

ll getminmax(int i,ll x)
{
    ll ans = a[i];///不要写成  = x  -_-||
    for (int j=63;j>=1;j--) ans = max(ans,ans^lb[i][j]);
    if (ans<=x) return INF;
    for (int j=63;j>=1;j--){
        ll temp = ans^lb[i][j];
        if (temp>ans) continue;
        if (temp>x) ans = temp;
        else {
            for (int k=j-1;k>=1;k--)
                temp = max(temp,temp^lb[i][k]);
            if (temp>x) ans = temp; 
        }
    }
    return ans;
}

int main()
{
    int n;
    while (~scanf("%d",&n)){
        memset(lb,0,sizeof lb);
        memset(dp,INF,sizeof dp);
        for (int i=1;i<=n;i++) scanf("%lld",a+i);
        for (int i=2;i<=n;i++){
            memcpy(lb[i],lb[i-1],sizeof lb[i-1]);
            get_lb(i,a[i-1]);
        }
        dp[1][1] = a[1];
        for (int i=2;i<=n;i++) dp[i][1] = min(getmin(i,a[i]),dp[i-1][1]);

        for (int i = 2;i<=n;i++)
            for (int j=2;j<=i;j++)
                if (dp[i-1][j-1]==INF) break;
                else dp[i][j] = min(dp[i-1][j],getminmax(i,dp[i-1][j-1]));
/*
        for (int i = 1;i<=n;i++){
            for (int j=1;j<=i;j++){
                if (dp[i][j]==INF) printf("dp[%d][%d]=INF  ",i,j);
                else printf("dp[%d][%d]=%lld  ",i,j,dp[i][j]);
            }
            printf("\n");
        }
*/
        for (int i=n;i>=1;i--){
            if (dp[n][i]!=INF){
                printf("%d\n",i);
                break;
            }
        }
    }
    return 0;
}

 

 

 

 

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
资源包主要包含以下内容: ASP项目源码:每个资源包中都包含完整的ASP项目源码,这些源码采用了经典的ASP技术开发,结构清晰、注释详细,帮助用户轻松理解整个项目的逻辑和实现方式。通过这些源码,用户可以学习到ASP的本语法、服务器端脚本编写方法、数据库操作、用户权限管理等关键技术。 数据库设计文件:为了方便用户更好地理解系统的后台逻辑,每个项目中都附带了完整的数据库设计文件。这些文件通常包括数据库结构图、数据表设计文档,以及示例数据SQL脚本。用户可以通过这些文件快速搭建项目所需的数据库环境,并了解各个数据表之间的关系和作用。 详细的开发文档:每个资源包都附有详细的开发文档,文档内容包括项目背景介绍、功能模块说明、系统流程图、用户界面设计以及关键代码解析等。这些文档为用户提供了深入的学习材料,使得即便是从零开始的开发者也能逐步掌握项目开发的全过程。 项目演示与使用指南:为帮助用户更好地理解和使用这些ASP项目,每个资源包中都包含项目的演示文件和使用指南。演示文件通常以视频或图文形式展示项目的主要功能和操作流程,使用指南则详细说明了如何配置开发环境、部署项目以及常见问题的解决方法。 毕业设计参考:对于正在准备毕业设计的学生来说,这些资源包是绝佳的参考材料。每个项目不仅功能完善、结构清晰,还符合常见的毕业设计要求和标准。通过这些项目,学生可以学习到如何从零开始构建一个完整的Web系统,并积累丰富的项目经验。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值