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;
}