超级翻转
(File IO)input:turn.in output:turn.out
Description
Input
Output
Sample Input
3
1
1
1 1
2
0 1
1 0
2 2
7
1 1 0 0 1 0 1
1 1 0 1 0 1 1
1 0 1 0 1 1 1
0 1 0 1 1 0 1
1 1 1 1 1 1 1
1 1 1 1 1 1 1
1 1 1 1 1 1 1
1 1
Sample Output
R
ULDR
No Solution!
Data constraint
线性基引入
对于线性基,我有这样的理解:
线性基一般是用来处理异或的问题的
性质
对于一个数组a,有一个对应线性基l
它有以下性质:
1. a中选任意数的异或都可以由l中选任意数异或成
2. l中任意数的异或不会与另一些数的异或相同
3. l包含
log(max{ai})
个二进制数,第i个二进制有i位,最高位为i
4. 若线性基中的1~k位都有数,那么它一定可以异或成
[1,2k−1]
的任意数
5. 线性基中取任意低位的数去异或高位的数,线性基的以上性质不变
操作
插入
将一个数v插入线性基,对v按高位到低位枚举,对于v的第i位v[i]=1若
l[i]=nil
则将v放入l[i],否则让
v=vxorl[i]
v是否能成功插入取决于v是否不能被线性基构成,若能被构成,最后v=0,否则
v≠0
且v放入了某个l[i]
同时v的最后取值能判断v是否能被线性基构成
//插入
bool insert(long long val){
for(int i=60;i>=0;i--)
if(val>>i){
if(!a[i])){a[i]=val;break;}
val^=a[i];
}
return val;
}
//判断某数是否在线性基里
bool cover(long long val){
for(int i=60;i>=0;i--)
if(val>>i){
if(!a[i]){return 0;}
val^=a[i];
}
return val==0;
}
合并
将线性基b合并到线性基a
即将b的每一位都插入到a就好了
void merge(Linear_Basis &a,Linear_Basis b){
for(int i=62;i+1;i--)a.insert(b.a[i]);
}
求线性基最大能构成的数
枚举线性基每位,将该位的数异或当前答案去更新答案
long long max(){
long long ans=0;
for(int i=62;i+1;i--)
if(a[i]^ans>ans)ans^=a[i];
return ans;
}
求第k小能组成的数
根据性质5,我们可以将线性基内部的元素重构:
使得对于第i位为1的数只能出现在线性基的第i个数
那么就可以根据k的2进制去求第k小
void rebuild(){
for(int i=62;i+1;i--)for(int j=i-1;j+1;j--)if(a[i]&1LL<<j)a[i]^=a[j];
for(int i=0;i<63;i++)if(a[i])p[cnt++]=a[i];
}
long long kth(long long k){
if(cnt<=1LL<<k)return -1;
long long ans=0;
for(int i=0;i<cnt;i++)if(k&1LL<<i)ans^=p[i];
return ans;
}
All:
struct Linear_Basis{
long long a[63],p[63];
int cnt;
void clear(){
for(int i=0;i<63;i++)a[i]=p[i]=0;cnt=0;
}
bool insert(long long val){
for(int i=62;i+1;i--)
if(val>>i&1){
if(!a[i]){a[i]=val;return 0;}
val^=a[i];
}return 1;
}
bool cover(long long val){
for(int i=62;i+1;i--)
if(val>>i&1){
if(!a[i])return 0;
val^=a[i];
}return 1;
}
long long max(){
long long ans=0;
for(int i=62;i+1;i--)
if(a[i]^ans>ans)ans^=a[i];
return ans;
}
void rebuild(){
for(int i=62;i+1;i--)for(int j=i-1;j+1;j--)if(a[i]&1LL<<j)a[i]^=a[j];
for(int i=0;i<63;i++)if(a[i])p[cnt++]=a[i];
}
long long kth(long long k){
if(cnt<=1LL<<k)return -1;
long long ans=0;
for(int i=0;i<cnt;i++)if(k&1LL<<i)ans^=p[i];
return ans;
}
};
void merge(Linear_Basis &a,Linear_Basis b){
for(int i=62;i+1;i--)a.insert(b.a[i]);
}
解题思路
枚举终点,翻转一下路径周围,我们有以下发现:
那么我们将每一个格子翻转的影响放入线性基,并记录某状态可以由那些格子影响构成(再开一个bitset储存),那么枚举终点时只用判断改状态是否在线性基里,取出构成状态,求答案就好了
怎么求答案??很简单输出枚举的路,在枚举每个影响到的点,输出路径,绕一圈,输出,原路返回到枚举的终点,输出
细节有一点点多
code:
#include<cstring>
#include<cstdio>
#include<cctype>
#include<cmath>
#include<algorithm>
#include<iostream>
#include<bitset>
using namespace std;
typedef bitset<225> BS;
struct lb{
BS d,p;
void clearmem(){
for(int i=0;i<225;i++)p[i]=0;
}
void clearall(){
for(int i=0;i<225;i++)d[i]=p[i]=0;
}
};
lb state[226],temp;
int n,T,path[226],Tot;
struct LB{
lb a[225];
bool insert(lb val){
for(int i=224;i>=0;i--)
if(val.d[i]){
if(a[i].d.none()){a[i]=val;break;}
val.d^=a[i].d;val.p^=a[i].p;
}
return val.d.any();
}
bool cover(lb val){
temp.clearmem();
for(int i=224;i>=0;i--)
if(val.d[i]){
if(a[i].d.none()){break;}
val.d^=a[i].d;temp.p^=a[i].p;
}
return val.d.none();
}
void clear(){
for(int i=0;i<225;i++)a[i].clearall();
}
}all;
bool find(int x,int y,int &tx,int &ty,int d){
if(all.cover(state[0])){state[0].p=temp.p;tx=x;ty=y;return 1;}else state[0].clearmem();
if(d<=1 && x>1){
if(y>1)state[0].d.flip((x-2)*n+y-2);if(y<=n)state[0].d.flip((x-2)*n+y-1);
if(find(x-1,y,tx,ty,1)){path[++Tot]=1;return 1;}
if(y>1)state[0].d.flip((x-2)*n+y-2);if(y<=n)state[0].d.flip((x-2)*n+y-1);
}
if((d==0 || d==2)&& x<=n){
if(y>1)state[0].d.flip((x-1)*n+y-2);if(y<=n)state[0].d.flip((x-1)*n+y-1);
if(find(x+1,y,tx,ty,2)){path[++Tot]=2;return 1;}
if(y>1)state[0].d.flip((x-1)*n+y-2);if(y<=n)state[0].d.flip((x-1)*n+y-1);
}
if(d!=4 && y<=n){
if(x>1)state[0].d.flip((x-2)*n+y-1);if(x<=n)state[0].d.flip((x-1)*n+y-1);
if(find(x,y+1,tx,ty,3)){path[++Tot]=3;return 1;}
if(x>1)state[0].d.flip((x-2)*n+y-1);if(x<=n)state[0].d.flip((x-1)*n+y-1);
}
if(d!=3 && y>1){
if(x>1)state[0].d.flip((x-2)*n+y-2);if(x<=n)state[0].d.flip((x-1)*n+y-2);
if(find(x,y-1,tx,ty,4)){path[++Tot]=4;return 1;}
if(x>1)state[0].d.flip((x-2)*n+y-2);if(x<=n)state[0].d.flip((x-1)*n+y-2);
}
return 0;
}
void write(int fx,int fy,int tx,int ty){
for(int i=fx;i<tx;i++)printf("D");
for(int i=fy;i<ty;i++)printf("R");
for(int i=ty;i<fy;i++)printf("L");
for(int i=tx;i<fx;i++)printf("U");
}
void walk(int fx,int fy,int tx,int ty,int w){
int x=-1,y=-1,W;
for(int i=1,t=0;i<=n;i++){
int p=0;
for(int j=1;j<=n;j++,t++)if(t>w && state[0].p[t]){W=t,x=i,y=j;p=1;break;}
if(p)break;
}
write(fx,fy,tx,ty);printf("RDLU");if(x>0 && y>0)walk(tx,ty,x,y,W);write(tx,ty,fx,fy);
}
int main(){
freopen("turn.in","r",stdin);
freopen("turn.out","w",stdout);
scanf("%d",&T);
for(int I=T;I;I--){
if(I<T)printf("\n");
int tot=0,x,y,tx,ty;Tot=0;
all.clear();
scanf("%d",&n);
temp.clearall();for(int i=0;i<=n*n;i++)state[i].clearall();
for(int k=0;k<n*n;k++)state[0].d[k]=state[0].p[k]=0;
for(int i=1;i<=n;i++)for(int j=1;j<=n;j++){
int x;scanf("%d",&x);state[0].d[tot++]=x;
for(int k=0;k<n*n;k++)state[tot].d[k]=state[tot].p[k]=0;
if((tot-1)%n!=0)state[tot].d[tot-2]=1;
if(tot%n!=0)state[tot].d[tot]=1;
if(tot>n)state[tot].d[tot-n-1]=1;
if(tot+n<=n*n)state[tot].d[tot+n-1]=1;
state[tot].p[tot-1]=1;
all.insert(state[tot]);
}
scanf("%d %d",&x,&y);
if(!find(x,y,tx,ty,0)){printf("No Solution!");continue;}
for(int i=Tot;i;i--){
if(path[i]==1)putchar('U');
if(path[i]==2)putchar('D');
if(path[i]==3)putchar('R');
if(path[i]==4)putchar('L');
}
if(state[0].p.none())continue;
for(int i=1,t=0;i<=n;i++){
int p=0;
for(int j=1;j<=n;j++,t++)if(state[0].p[t]){walk(tx,ty,i,j,t);p=1;break;}
if(p)break;
}
}
fclose(stdin);fclose(stdout);
return 0;
}