Description

由于小凯上次在找零问题上的疑惑,给大家在考场上带来了很大的麻烦,他决心好好学习数学
本次他挑选了位运算专题进行研究 他发明了一种叫做“小凯运算”的运算符:
a$b =( (a&b) + (a|b) )>>1
他为了练习,写了n个数在黑板上(记为a[i]) 并对任意相邻两个数进行“小凯运算”,把两数擦去,把结果留下 这样操作n-1次之后就只剩了1个数,求这个数可能是什么?
将答案从小到大顺序输出

Input

4
1 4 3 2

Output

1 2

Sample Input

4
1 4 3 2

Sample Output

1 2

Data Constraint

​ 30% n<=10 0<=a[i]<=7
70% n<=150 0<=a[i]<=3
100% n<=150 0<=a[i]<=7

思路

区间DP
设f[i][j][0…7]为区间i…j能否合成0…7

于是枚举断点,再枚举转移点即可

代码

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int inf=0x3f3f3f3f;
int s=0,ss=inf,n;
int f[157][157][8];
int main()
{
	freopen("math.in","r",stdin); freopen("math.out","w",stdout);
	scanf("%d",&n);
	for(int i=1; i<=n; i++)
	{
		int x;
		scanf("%d",&x); f[i][i][x]=1; s=max(x,s); ss=min(ss,x);
	}
	for(int i=2; i<=n; i++) for(int j=1; j<=n-i+1; j++)
	{
		int l=j,r=j+i-1;
		for(int k=j; k<=j+i-1; k++)
		{
			for(int x=ss; x<=s; x++) for(int y=x; y<=s; y++)
			{
				f[l][r][(x+y)>>1]|=(f[l][k][x]&f[k+1][r][y])|(f[k+1][r][x]&f[l][k][y]);
			}
		}
	}
	for(int i=ss; i<=s; i++) if(f[1][n][i]) printf("%d ",i);
}