Codeforces 1006F Xor-Paths 【搜索】【暴力】
一道暴力题,应该想到要么剪枝要么优化搜索方法。想了想不会剪枝,所以确定这道题考的是怎么搜。
首先暴搜的话复杂度是C(n+m,n),直接炸了。
后来想到优化是分别从起点和终点搜到一半的位置,这个时候分析。那么对于中间行【mid=(n+1)/2】上的每个点来说有一棵从(1,1)到这个点的搜索树和(n,m)到这个点的搜索树。我们考虑(mid,1)这个点,从(1,1)到它的搜索树只有一种可能C(mid,mid);从(n,m)到它的有C(n+m-mid,mid)=>C(m+n/2,n/2)级别的搜索树,那最差是C(30,10)。也炸了。
【这个算法不行的本质是上下两个搜索树相差太大】
【相对暴搜节省了时间的本质是省去了对于上搜索树的每一个路径都枚举出下搜索树的每个路径】
从搜索树相差太大入手,我们用meet in mid的方法,还想让两棵搜索树一样大。已知从起点到终点一共要走n+m-2步,所以我们让每个搜索树都搜索(n+m-2)/2步就可以了。复杂度最差是2^(n+m-2)/2【枚举每一步是往下走还是往右走】,也就是2^19稳稳过。
1 #include<iostream> 2 #include<map> 3 using namespace std; 4 5 long long a[25][25],ans,k,x1[25]; 6 int n,m,mid; 7 8 map<long long, int> mp[25][25]; 9 10 void dfs1(int x,int y,long long k1,int cnt){//从x,y的位置搜到中间行 == k1是一路上^得到的数 包括(x,y) 11 if(cnt==mid) mp[x][y][k1]++; 12 else if(y==m) dfs1(x+1,y, k1^a[x+1][y],cnt+1 ); 13 else if(x==n) dfs1(x,y+1, k1^a[x][y+1],cnt+1 ); 14 else { dfs1(x+1,y,k1^a[x+1][y],cnt+1); dfs1(x,y+1,k1^a[x][y+1],cnt+1); } 15 } 16 17 void dfs2(int x,int y,long long k1,int cnt){ 18 if(cnt==n+m-2-mid) ans+=mp[x][y][k^k1]; 19 else if(y==1) dfs2(x-1,y, k1^a[x][y],cnt+1 ); 20 else if(x==1) dfs2(x,y-1, k1^a[x][y],cnt+1 ); 21 else { dfs2(x,y-1,k1^a[x][y],cnt+1); dfs2(x-1,y,k1^a[x][y],cnt+1); } 22 } 23 24 int main(){ 25 cin>>n>>m>>k; 26 for(int i=1;i<=n;i++) 27 for(int j=1;j<=m;j++) cin>>a[i][j]; 28 29 mid=(n+m-2)/2;//一共要走n+m-2次,走了一半的次数走到哪哪就定义成中间行的一部分 30 //从(1,1)搜到中间那一行 31 dfs1(1,1,a[1][1],0); 32 //从(n,m)搜到中间那一行 33 dfs2(n,m,0,0); 34 cout<<ans; 35 return 0; 36 }