【JZOJ 5284】 超级翻转

来源:互联网 发布:淘宝网 电脑版 登录 编辑:程序博客网 时间:2024/06/05 06:38

Description

这里写图片描述
这里写图片描述
1<=n<=15,1<=数据组数<=5

Analysis

这种题,发现数据范围暴力过不了,就应该发掘一下移动的性质

  • 显然一条边走的次数可以简化成0/1
  • 一个格子的状态取决于其相邻四条边走的次数异或

这样可以对每个格子列出方程,不过并不知道这个idea可不可做
继续发掘

  • 如果一个点四周被绕了一圈,那么造成的影响仅是这个格子四周的格子反色

并且,由于我们可以从起点走到一个点绕一圈再原路反回来,所以走原路返回的时候经过的那些边相当于不计影响
这就是个很好的性质了,不论起点在哪,我们都可以任意选定格子,造成的贡献是四周的格子反色
这就有点像这题了
不过也可能不绕圈啊!!!
TM就GG没关系,我们枚举一个终点
那么起点到终点必定会有一条路径,这条路径是什么?
在路径上绕一个圈试试?
路径刚好进行了偏移,归纳一发,我们可以通过选择点绕圈来更改路径(感性)
那么暴力走一遍,暴力反色,就变成上面那个题了
然后应该就能过了,复杂度应该是n32n,实际跑得挺快

你以为这样就完了?

一个巨大的优化

这里写图片描述
选红勾的格子等价于选蓝勾的格子
我们不需要枚举第一行的状态
存在一种可行解,第一行全不选
复杂度变成n3

Code

#include<cstdio>#include<cstring>#include<algorithm>#define fo(i,a,b) for(int i=a;i<=b;i++)#define fd(i,b,a) for(int i=b;i>=a;i--)#define max(x,y) ((x)>(y)?(x):(y))#define min(x,y) ((x)<(y)?(x):(y))#define mset(a,x) memset(a,x,sizeof(a))using namespace std;typedef long long ll;const int N=20;int n,xs,ys,xt,yt,a[N][N],b[N][N],c[N][N];//c:a matrix,value 1/0 standing node(i,j) is choosen or notvoid go(int xs,int ys,int xt,int yt){    int fx=xs<xt?1:-1;    for(;xs!=xt;xs+=fx)        if(fx==1) b[xs][ys-1]^=1,b[xs][ys]^=1;        else b[xs-1][ys-1]^=1,b[xs-1][ys]^=1;    fx=ys<yt?1:-1;    for(;ys!=yt;ys+=fx)        if(fx==1) b[xs-1][ys]^=1,b[xs][ys]^=1;        else b[xs-1][ys-1]^=1,b[xs][ys-1]^=1;    fo(i,0,n+1) b[i][0]=b[0][i]=b[i][n+1]=b[n+1][i]=0;}void output(int xs,int ys,int xt,int yt,int p){    int fx;    if(!p)    {        fx=xs<xt?1:-1;        for(;xs!=xt;xs+=fx) putchar(fx==1?'D':'U');        fx=ys<yt?1:-1;        for(;ys!=yt;ys+=fx) putchar(fx==1?'R':'L');    }    else    {        fx=ys<yt?1:-1;        for(;ys!=yt;ys+=fx) putchar(fx==1?'R':'L');        fx=xs<xt?1:-1;        for(;xs!=xt;xs+=fx) putchar(fx==1?'D':'U');    }}int main(){    freopen("turn.in","r",stdin);    freopen("turn.out","w",stdout);    int T;    for(scanf("%d",&T);T;T--)    {        scanf("%d",&n);        fo(i,1,n)            fo(j,1,n) scanf("%d",&a[i][j]);        scanf("%d %d",&xs,&ys);        bool p=0;        for(xt=1;xt<=n+1;xt++)        {            for(yt=1;yt<=n+1;yt++)            {                memcpy(b,a,sizeof(a));                go(xs,ys,xt,yt);                mset(c,0);                fo(i,2,n)//it can be proved that the first line of c can be all 0                    fo(j,1,n)                        c[i][j]=c[i-1][j-1]^c[i-2][j]^c[i-1][j+1]^b[i-1][j];                bool ok=1;                fo(i,1,n)                    if(c[n][i-1]^c[n-1][i]^c[n][i+1]^b[n][i]) {ok=0;break;}                if(!ok) continue;                p=1;break;            }            if(p) break;        }        if(!p) {puts("No Solution!");continue;}        fo(i,1,n)            fo(j,1,n)                if(c[i][j])                {                    output(xs,ys,i,j,0);                    printf("RDLU");                    output(i,j,xs,ys,1);                }        output(xs,ys,xt,yt,0);printf("\n");    }    return 0;}
原创粉丝点击