lg P4310 绝世好题

题目链接: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;
 } 

猜你喜欢

转载自www.cnblogs.com/Beic233/p/12699382.html