题目链接:https://www.luogu.com.cn/problem/P4310
子列和字串:通俗来讲,子列可以不连续,字串必须连续
方法一(90分)
像求最长连续子列,直接暴力n^2
这里提一下:按位与(&)的优先级是没有等于号( == )或者不等号(!=)高的,如果直接在if语句里面运算,记得加括号
#include <iostream>
#include <cstdio>
using namespace std;
const int maxn = 1e5+50;
int a[maxn],dp[maxn];
int main()
{
//freopen("in.txt","r",stdin);
int n,ans = 0;
cin>>n;
for(int i = 1; i <= n; i++){
cin>>a[i];
int k = 1;
for(int j = 1; j < i; j++){
int cnt = a[i] & a[j];
if(cnt != 0) k = max(k,dp[j]+1);
}
dp[i] = k;
ans = max(ans,k);
}
// for(int i = 1; i <= n; i++) cout<<dp[i]<<" ";
cout<<ans;
return 0;
}
方法二:
dp[i] 表示在当前数下的二进制的第i位的最长长度
如果想要 b[i] & b[i-1] != 0 那么b[i] 和 b[i-1] 的二进制肯定有某个数位上的数同时为1,所以对于我们当前拿到一个数num,我们去遍历他的二进制数位,如果他的第j个二进制数位上的数是1,那么我们就可以取dp[j] ,此时dp[j] 里面存的是在num之前所有的数中符合题意的最大长度,我们只需要遍历num所有的数位然后取个最大的,最后在去更新dp就行了
检查b的二进制的第k位是0还是1的方法:b & (1<<k)
#include <iostream>
#include <cstdio>
using namespace std;
const int maxn = 1e5+50;
int dp[maxn];
int main()
{
freopen("in.txt","r",stdin);
int n,ans = 0;
cin>>n;
for(int i = 1; i <= n; i++){
int b,cnt = 1;
cin>>b;
for(int k = 0; k <= 30; k++) if(b & (1<<k)) cnt = max(cnt,dp[k]+1);
for(int k = 0; k <= 30; k++) if(b & (1<<k)) dp[k] = max(dp[k],cnt);
ans = max(ans,cnt);
}
cout<<ans;
return 0;
}