2020-08-21
http://icpc.upc.edu.cn/problem.php?cid=2552&pid=0
题目描述
经过数天的艰苦跋涉,Rainy7 终于进入了魔法王国。由于 Rainy7 是大魔法师,所以她受到了国王 3edc2wsx1qaz 的热情款待。
Rainy7 享用完国宴后,国王向她道出了魔法王国的困难:王国正遭受着魔兽的袭击。王国中的所有人都无法击败魔兽,所以国王恳请大魔法师 Rainy7 帮助王国与魔兽战斗。
Rainy7 爽快地答应了。国王欣喜若狂,并立即邀请 Rainy7 到魔法世界最大的魔法阵中汲取魔法,以做好战斗准备。
这个魔法阵是一个n行m列的矩阵,矩阵中每个格子都有一个非负整数的魔法值,第i行第j列的格子的魔法值为aij。
Rainy7 要从第1行第1列的格子走到第n行第m列的格子。如果 Rainy7 当前在第i行第j列的格子上,则她下一步可以走到第i+1行第j列的格子或第 i行第j+1列的格子上(如果那个格子存在的话),直到她走到第n行第m列的格子为止。
Rainy7 只能按这样的方式走一次。走完后,Rainy7 汲取到的魔法值是她走过的所有格子的魔法值的与和,即把她走过的所有格子的魔法值全部按位与起来的结果。
Rainy7 想知道她最多能汲取到多少魔法值。Rainy7 只用了114514-1919810s就算出了答案,在她开始汲取魔法之前,她也想让你解决这个问题。
顷刻间,魔法汲取完毕了,Rainy7 便坚定地向战场走去……
输入
第一行两个整数n,m,分别表示魔法阵的行数和列数。
接下来n行,每行包含m个整数,其中第i的第j个数表示aij。
输出
输出一行一个整数,表示 Rainy7 能汲取到的魔法值的最大值。
样例输入
【样例1】
3 4
3 7 7 7
6 3 8 4
1 3 3 7
【样例2】
10 10
2047 2047 1535 2043 863 1983 2046 2015 2047 2047
1903 1535 1982 2015 2047 1531 1791 2015 2025 2045
767 927 2023 2039 2015 1918 2042 2039 935 2047
2022 2045 1499 991 2046 2047 2047 959 1023 2047
2038 1999 2046 1919 1519 2015 1007 2047 2047 1023
2047 991 1983 2047 1919 1655 1791 2013 1535 2047
2047 2047 1974 1535 2047 2031 1847 1535 2047 2045
1023 1023 2047 2047 1919 2011 1983 1791 1979 2023
2047 2047 2047 2045 1503 511 1023 2004 2039 2047
895 1525 2031 1911 2039 1967 1852 1023 1983 2047
样例输出
【样例1】
3
【样例2】
1284
提示
样例1解释:
我们用(i,j)表示魔法阵第i行第j列的格子。
Rainy7 走过的路径为:(1,1)->(1,2)->(2,2)->(3,2)->(3,3)->(3,4),汲取到的魔法值为 3 and 7 and 3 and 4 and 3 and 7 = 3。
样例2解释:
Rainy7 走过的一种最佳路径为:
(1,1)->(1,2)->(1,3)->(2,3)->(2,4)->(2.5)->(3,5)->(4,5)->(5,5)->(6,5)->(7,5)->(7,6)->(7,7)->(7,8)->(7,9)->(7,10)->(8,10)->(9,10)->(10.10)。
对于全部数据,1≤n,m≤2×103,0≤aij≤231-1。
#pragma GCC optimize(1)
#pragma GCC optimize(2)
#pragma GCC optimize(3,"Ofast","inline")
#include
using namespace std;
typedef long long ll;
int a[2500][2500]= {0};
int n,m;
int dp[2500][2500]= {0};
int max1=0;
int cnt=0;
int p[2005][2005]={0};
int vis[2005][2005]={0};
inline int dfs()
{
if(vis[1][1])
return 0;
cnt++;
p[1][1]=cnt;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
if(vis[i][j])
continue;
if(i>1&&!vis[i-1][j]&&p[i-1][j]==cnt)
p[i][j]=cnt;
if(j>1&&!vis[i][j-1]&&p[i][j-1]==cnt)
p[i][j]=cnt;
}
}
if(p[n][m]==cnt)
return 1;
else
return 0;
}
int last[2005][2005]={0};
int l[100]={0};
int main()
{
scanf("%d%d",&n,&m);
for(register int i=1; i<=n; i++)
{
for(register int j=1; j<=m; j++)
{
scanf("%d",&a[i][j]);
}
}
for(int k=31;k>=0;k--)
{
if(!((a[1][1]>>k)&1))
continue;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
vis[i][j]=last[i][j];
}
}
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
if(!((a[i][j]>>k)&1))
vis[i][j]=1;
}
}
if(dfs())
{
l[k]=1;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
last[i][j]=vis[i][j];
}
}
}
}
int sum=0;
for(int i=30;i>=0;i--)
{
sum+=l[i]*(1<<i);
}
cout<<sum<<endl;
return 0;
}