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 <bits/stdc++.h>
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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值