折半搜索

CodeForces-1006F Xor-Paths


有n x m个网格,网格值为a(i,j),从(1,1)走到(n,m),每次只能向右走或者向下走,将经过的格子的值全部异或起来,求走到(n,m)时异或值为k的走法有多少种

输入:
n、m:n x m的网格
k:要求得到的异或值
n行,每行m个:网格a(i,j)的值

输出:从(1,1)走到(n,m),最后异或值为k的走法有多少种


直接从(1,1)深搜到(n,m)会TLE,采用折半搜索:从(1,1)深搜到中点,从终点(n,m)深搜到中点

因为n,m均可取1,所以中点不能取(n+m)/2而要取(n+m+2)/2

另:一开始用vector储存从(1,1)走到中点的值时TLE了,大概是因为遍历vector中元素提高了时间复杂度

因为走到某个x值时其y值一定是固定的,可以直接使用mp[x][price]存(price是走到a[x][y]时得到的异或值)

再有,要判断mp[x][mm]是否为空(mp[x].size()!=0也ac了,emmm),否则会越界访问Runtime error


/*折半搜索*/
/*CodeForces-1006F*/
#include<bits/stdc++.h>
using namespace std;

#define ll long long
#define pb push_back
#define PI acos(-1.0)

int n,m;
ll k;
map<ll,ll> mp[25];
ll num[25][25];
ll sum;

void dfs1(int x,int y,ll price)
{
    if(x+y>(n+m+2)/2) return;
    if(x+y==(n+m+2)/2)
    {
        price=price^num[x][y];
        mp[x][price]++;
        return;
    }
    else
    {
        ll t=price^num[x][y];
        dfs1(x+1,y,t);
        dfs1(x,y+1,t);
    }
}
void dfs2(int x,int y,ll price)
{
    if(x+y<(n+m+2)/2) return;
    if(x+y==(n+m+2)/2)
    {
        ll mm=price^k;
        if(mp[x].size()!=0)
            sum+=mp[x][mm];
        return;
    }
    else
    {
        ll t=price^num[x][y];
        dfs2(x-1,y,t);
        dfs2(x,y-1,t);
    }

}


int main()
{
    scanf("%d%d",&n,&m);
    scanf("%I64d",&k);
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
        {
            scanf("%I64d",&num[i][j]);
        }
    }
    dfs1(1,1,0);
    sum=0;
    dfs2(n,m,0);
    printf("%I64d\n",sum);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/z26y25j10/article/details/81508945
今日推荐