[JZOJ5284] 超级翻转

来源:互联网 发布:身份证复制软件打不开 编辑:程序博客网 时间:2024/06/07 15:09

Description

这里写图片描述
这里写图片描述
这里写图片描述

输出任意一种即可,题目有SPJ

Solution

可以考虑先枚举终点。

那么一条路径我们可以通过绕圈来修改它

具体而言,从任意一个点,走到一个格子的左上角,绕着这个格子走一圈,再原路返回,这样相当于只将这个格子四个方向的格子取反

对于起点到枚举的终点的路径,随便怎么走,都可以通过上面绕格子的方式修改成所有的路径

那么枚举终点随便走了一条路径后,原问题转化成可以选择一些格子,将这个格子四周取反,求使所有格子变成白色的方案。

显然操作顺序没有影响,考虑按1~N行做

发现当前行的操作状态完全由上一行决定,因为过了这一行再也没有能修改前一行的操作了

那么上一行的状态前移、后移一位异或上当前行就是当前行的状态,同时对下一行也产生影响,下一行也异或上它

那么当做到最后一行全为0时输出,否则当前枚举的终点无解,继续枚举

关键是第一行的状态

可以枚举,但是复杂度比较大

事实上,第一行全部都不用选,因为可以选择其他行的一些格子,最终的状态与选择第一行的格子等价

因为原矩阵是正方形
这里写图片描述
这里写图片描述
选红色格子,对蓝色格子取反

可以发现选所有的绿色格子,和选红色的格子的影响是等价的

那么第一行就可以全不选

有道题叫玩诈欺的小杉,和这题转化后非常相似
话说那是我最早写的几篇Blog之一。。。。
http://blog.csdn.net/hzj1054689699/article/details/50571564

Code

#include <cstdio>#include <iostream>#include <cstring>#include <cstdlib>#include <iostream>#include <cmath>#define fo(i,a,b) for(int i=a;i<=b;i++)#define fod(i,a,b) for(int i=a;i>=b;i--)#define N 16using namespace std;int b[N],a[N],n,rd[N];void walk(int x,int y,int p,int q){    if(x>p) printf("U"),walk(x-1,y,p,q);    else if(y>q) printf("L"),walk(x,y-1,p,q);    else if(y<q) printf("R"),walk(x,y+1,p,q);    else if(x<p) printf("D"),walk(x+1,y,p,q);}void fx(int x,int y) {    b[x]^=(1<<(y-1));}void chd(int x,int y){    if(y<=n) fx(x,y);    if(y>1) fx(x,y-1); }void chh(int x,int y){    if(x<=n) fx(x,y);    if(x>1) fx(x-1,y);}void wk(int x,int y,int p,int q){    if(x>p) chd(x-1,y),wk(x-1,y,p,q);    else if(y>q) chh(x,y-1),wk(x,y-1,p,q);    else if(y<q) chh(x,y),wk(x,y+1,p,q);    else if(x<p) chd(x,y),wk(x+1,y,p,q);}int main(){    int t;    cin>>t;    while(t--)    {        memset(b,0,sizeof(b));        memset(a,0,sizeof(a));        scanf("%d",&n);        if(n==1)         {            int v,p,q;            scanf("%d",&v);            scanf("%d%d",&p,&q);            if(v==0)printf("\n");            else            {                if(p==1) printf("D\n");                else printf("U\n");             }            continue;        }        fo(i,1,n)        {            fo(j,1,n) scanf("%d",&rd[n-j+1]);            fo(j,1,n)             {                b[i]=b[i]*2+rd[j];                a[i]=b[i];            }        }        int x,y,v=(1<<n),bp=0;        scanf("%d%d",&x,&y);        fo(p,1,n+1)        {            fo(q,1,n+1)            {                fo(i,1,n+1) b[i]=a[i];                wk(x,y,p,q);                fo(i,2,n)                {                    b[i]=b[i]^(b[i-1]*2%v)^(b[i-1]/2);                    b[i+1]=b[i+1]^b[i-1];                }                if(b[n]!=0) continue;                else                {                    bp=1;                    walk(x,y,p,q);                    fo(i,2,n)                    {                        fo(j,1,n)                        {                            if(b[i-1]&((1<<(j-1))))                            {                                walk(p,q,i,j);                                printf("RDLU");                                walk(i,j,p,q);                            }                        }                    }                    printf("\n");                    break;                }                if(bp)break;            }            if(bp) break;        }        if(!bp) printf("No Solution!\n");    }}
原创粉丝点击