【JZOJ5284】 超级翻转
2017-08-19 08:06
211 查看
超级翻转
(File IO)input:turn.in output:turn.outDescription
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; }
相关文章推荐
- 【JZOJ 5284】 超级翻转
- [JZOJ5284] 超级翻转
- 【JZOJ 5284】【清华集训2017模拟】超级翻转
- JZOJ 1331. 超级教主
- jzoj P1331 超级教主___dp+单调队列
- 【欧拉回路+高斯消元】超级翻转
- JZOJ 1331——超级教主【dp】
- 在线表格,推荐使用超级表格——超好用的电子表格
- Nginx超级简单入门
- 超级恶心的MSN
- nyoj 76 超级台阶
- 干货满满,绝不错过,DOM、BOM 操作超级集合
- FTP站点超级连接视图与文件夹视图的切换
- Android开发教程:文字翻转动画的实现
- jzoj 1360. 【2011.12.31普及模拟】逃离洞穴
- 从超级菜鸟变成Linux系统高手
- 今天下午干掉一个超级bug
- 翻转单词顺序
- 超级表格创始人中学时代揭秘
- JZOJ2017.08.12 C组