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;
}

 

 

 

 

 

 

Python网络爬虫与推荐算法新闻推荐平台:网络爬虫:通过Python实现新浪新闻的爬取,可爬取新闻页面上的标题、文本、图片、视频链接(保留排版) 推荐算法:权重衰减+标签推荐+区域推荐+热点推荐.zip项目工程资源经过严格测试可直接运行成功且功能正常的情况才上传,可轻松复刻,拿到资料包后可轻松复现出一样的项目,本人系统开发经验充足(全领域),有任何使用问题欢迎随时与我联系,我会及时为您解惑,提供帮助。 【资源内容】:包含完整源码+工程文件+说明(如有)等。答辩评审平均分达到96分,放心下载使用!可轻松复现,设计报告也可借鉴此项目,该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的。 【提供帮助】:有任何使用问题欢迎随时与我联系,我会及时解答解惑,提供帮助 【附带帮助】:若还需要相关开发工具、学习资料等,我会提供帮助,提供资料,鼓励学习进步 【项目价值】:可用在相关项目设计中,皆可应用在项目、毕业设计、课程设计、期末/期中/大作业、工程实训、大创等学科竞赛比赛、初期项目立项、学习/练手等方面,可借鉴此优质项目实现复刻,设计报告也可借鉴此项目,也可于此项目来扩展开发出更多功能 下载后请首先打开README文件(如有),项目工程可直接复现复刻,如果础还行,也可在此程序础上进行修改,以实现其它功能。供开源学习/技术交流/学习参考,勿用于商业用途。质量优质,放心下载使用。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值