1921: B
Time Limit: 1 Sec Memory Limit: 128 MBSubmit: 270 Solved: 31
Description
给定一个长度为n的数字序列a,从中选取一个长为m的子序列b满足 b[i]&b[i-1]!=0 (2<=i<=m)
求最大的m。
Input
第一行输入一个整数t,代表有t组测试数据。
每组数据第一行输入一个整数n代表a序列的长度,接下来一行输入n个正整数表示ai(0<i<=n)。
1<=t<=20,0<=n<=100000,0<=ai<=1e9。
Output
一个整数表示最大的m。
Sample Input
1
3
1 1 1
Sample Output
3
HINT
Source
这道题让我一脸懵逼状(⊙﹏⊙)b。又读错题了。。。。我以为是所有子列按位与运算。。。。我说怎么各种WA。。我说为嘛还要dp。。。。。
思路:
用dp记录当前状态下的每一位的最大值,对于序列中的元素, 如果这个数的第j为1, 他肯定要和前面的接上,这样就保证了他和相邻的按位与不为零,然后dp的值等于他后面的加上一。每次检查他的每一位的二进制状态,更新最值。
对于一维的转移方程为 for dp【i】 = max(dp【last】 + 1, dp【i】);
#include <bits/stdc++.h> using namespace std; const int BIT = 32; const int maxm = 100000 + 10; int a, dp[maxm], last[40]; void init() { memset(dp, 0, sizeof(dp)); memset(last, 0, sizeof(last)); } bool judge_bit(int x, int y) { if (x & (1<<y)) return true; return false; } int main() { int n, t; scanf("%d", &t); while(t--) { int ans = 0; scanf("%d", &n); init(); for(int i = 1; i <= n; i++) { scanf("%d", &a); for(int j = 0; j <= BIT; j++) { if(judge_bit(a, j)) { dp[i] = max(dp[last[j]] + 1, dp[i]); //last记录的是上一次 j 位为 1的位置 last[j] = i; } } ans = max(ans, dp[i]); } printf("%d ", ans); } return 0; }