题目
由于wangjp小学生数学题都不会做,给大家在考场上带来了很大的麻烦,他决心好好学习数学
本次他挑选了位运算专题进行研究 他发明了一种叫做“wangjp运算”的运算符:a$b =( (a&b) + (a|b) )>>1他为了练习,写了n个数在黑板上(记为a[i]) 并对任意相邻两个数进行“wangjp运算”,把两数擦去,把结果留下 这样操作n-1次之后就只剩了1个数,
这个数可能是什么?
将答案从小到大顺序输出
30% n<=10 0<=a[i]<=7 70% n<=150 0<=a[i]<=3 100% n<=150 0<=a[i]<=7
题解
暴力或观察数据可得部分分
正解动规
设f[i][j][0~ 7]表示区间[i,j]可不可以达成数0~7
易得转移方程
为了省时间,运算过程用位运算且用bool型存动规判定数组。观察数据可发现实际上a$b =( (a&b) + (a|b) )>>1就是(a+b)/2
代码
#include <cstdio>
#include <iostream>
using namespace std;
int n,b,c,d,m;
int a[200];
bool f[200][200][10];
int main(){
scanf("%d",&n);
for (int i=1;i<=n;i++){
scanf("%d",&a[i]);
if (a[i]>1) b=1;
if (a[i]>m) m=a[i];
if (a[i]!=3) d=1;
if (a[i]==0) c=1;
f[i][i][a[i]]=1;
}
if (!b&&c) {printf("0");return 0;}
if (!d) {printf("3");return 0;}
for (int e=2;e<=n;e++)
for (int i=1;i+e-1<=n;i++){
int l=i,r=i+e-1;
for (int k=0;k<=m;k++)
for (int t=0;t<=m;t++)
for (int j=l;j<r;j++)
f[l][r][(k+t)>>1]|=f[l][j][k]&f[j+1][r][t];
}
int c;
for (c=0;c<=m;c++)
if (f[1][n][c]) printf("%d ",c);
}