HDU 5416 CRB and Tree (DFS)

DFS这棵树,对于每个点u算出从根节点到这个点总共的异或值val[u],并记录每个值的数量。


因为异或的性质:

1.对于u到v的这条路,不管是u,v在根节点出发的同一条路上还是两条路上,f(u,v)都等于k[u]^k[v]。

2.s^t=k,则t^k=s。

且询问只有10组,那么对于每个询问s,可以用遍历0到200000的所有值i,算出和每个值异或等于s的那个对应的值k,然后答案加上num[i]*num[k],如果i==k那么要加num[i]*(num[k]-1)。最后答案除2。


注意:

遍历值时要遍历到200000而不是100000,因为N以内的数互相异或的最大值一定不会超过N*2

num[i]*num[k]会爆int


代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#include <set>
#include <cmath>
#define LL long long
#define maxn 505
#define bug(a) cout<<a<<endl;
#define bg cout<<'!'<<endl;
const LL mod = 1e9+7;
LL dp[2][maxn][maxn];


char mp[maxn][maxn];
int n,m;

bool valid(int x,int y){
    if(x<=n-1&&x>=0&&y<=m-1&&y>=0) return 1;
    return 0;
}

int main(){
    scanf("%d%d",&n,&m);
    for(int i=0;i<n;i++){
        char s[maxn];
        scanf("%s",s);
        for(int j=0;j<m;j++){
            mp[i][j]=s[j];
        }
    }
    if(mp[0][0]!=mp[n-1][m-1]){
        printf("0\n");
        return 0;
    }
    dp[0][0][n-1]=1;
    int tot=(m+n-2)/2;
    int cur=0;
    for(int i=1;i<tot;i++){
        cur^=1;
        for(int j=0;j<=i;j++){
            int x1=i-j,y1=j;
            if(!valid(x1,y1)) continue;
            for(int k=0;k<=i;k++){
                int x2=n-1-i+k,y2=m-1-k;

                if(!valid(x2,y2)) continue;
                bug(x1);bug(y1);bug(x2);bug(y2);
                if(mp[x1][y1]==mp[x2][y2]){
                    if(x1){
                        dp[cur][x1][x2]+=(dp[cur^1][x1-1][x2])%=mod;
                        dp[cur][x1][x2]+=(dp[cur^1][x1-1][x2+1])%=mod;
                    }
                    if(x2+1<n){
                        dp[cur][x1][x2]+=(dp[cur^1][x1][x2])%=mod;
                        dp[cur][x1][x2]+=(dp[cur^1][x1][x2+1])%=mod;
                    }
                }
            }
        }
    }
    LL res=0;
    if((m+n)&1){
        for(int i=0;i<n-1;i++){
            (res+=(dp[cur][i][i]))%=mod;
            res+=(dp[cur][i][i+1])%=mod;
        }
        res+=(dp[cur][n-1][n-1])%=mod;
    }
    else {
        for(int i=0;i<n-1;i++){
            (res+=(dp[cur][i][i+1]*2))%=mod;
        }
    }
    printf("%I64d\n",res);
    return 0;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值