【校内互侧】ZYF loves binary (dp)
ZYF loves binary(binary.cpp)
【问题描述】ZYF 无聊的时候喜欢研究二进制,她认为二进制的世界中只有三种运算:按位与(and)、按位或(or)和异或(xor)。
有一天她找来了 n个小伙伴并给他们每人一个权值 ai, 然后她发现第 i个人和第j 个人的友好程度可以表示为ai opt aj,其中 opt是三种运算的一种。
由于 ZYF忙着刷题所以想让你告诉她,对于从左到右的第2 到n 个人,他们左边与他们友好程度的最大值是多少,还有达到最大值的人数是多少。
【输入格式】
第一行包含一个整数 n,一个串opt 和一个整数type,分别表示人数,运算类型和数据类型。
第二行包含 n个整数,表示从左往右第 i个人的权值 ai。
【输出格式】
如果 type=0,输出 n-1 行,每行一个整数,其中第i 行输出和第i+1 个人友好程度的最大值。
如果 type=1,输出 n-1 行,每行两个整数,其中第i 行输出和第i+1 个人友好程度的最大值和达到最大值的人数。
【样例输入】
5 and 1
3 5 2 7 1
【样例输出】
1 1
2 1
5 1
1 3
【数据规模及约定】
对于 100%的数据,0<=ai<65536
_______________________________________________________________
【题解】【dp】
【通过看数据范围可知,a[i]最大为2的16次方,所以可以拆分为前八位和后八位来处理】
【f[i][j]表示前八位为i的数和后八位为j的数进行i opt j运算的最大值;g[i][j]表示前八位为i和后八位为j的数进行i opt j运算的最大值的方案数】
【加入一个数x的时候,设前8位为a,后8位为b,枚举j,用所有j opt b更新所有f[a][j]。】
【查询一个数x的时候,枚举所有i,用(i opt a)<<8|f[i][b]更新答案】
【复杂度O(2^8*n)】
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
char s[5];
int f[1<<8][1<<8],g[1<<8][1<<8],a[100010];
int n,opt;
inline int check(int x,int y,int j)
{
if(s[0]=='a') return ((x&j)<<8|f[j][y]);
if(s[0]=='x') return ((x^j)<<8|f[j][y]);
if(s[0]=='o') return ((x|j)<<8|f[j][y]);
}
inline int slove(int y,int j)
{
if(s[0]=='a') return (y&j);
if(s[0]=='x') return (y^j);
if(s[0]=='o') return (y|j);
}
int main()
{
freopen("binary.in","r",stdin);
freopen("binary.out","w",stdout);
int i,j;
scanf("%d%s%d",&n,s,&opt);
for(i=1;i<=n;++i) scanf("%d",&a[i]);
memset(f,-1,sizeof(f));
memset(g,0,sizeof(g));
for(i=1;i<=n;++i)
{
int x=a[i]>>8,y=a[i]%(1<<8);
int maxn=-1,num=0;
if(i!=1)
{
for(j=0;j<=(1<<8)-1;++j)
{
int t=check(x,y,j);
if(t>maxn) {maxn=t,num=g[j][y]; continue; }
if(t==maxn) {num+=g[j][y]; continue; }
}
if(opt) printf("%d %d\n",maxn,num);
else printf("%d\n",maxn);
}
for(j=0;j<=(1<<8)-1;++j)
{
int t=slove(y,j);
if(t==f[x][j]) {g[x][j]++; continue;}
if(t>f[x][j]) {f[x][j]=t,g[x][j]=1; continue;}
}
}
return 0;
}
既然无能更改,又何必枉自寻烦忧