【暴力】【規律】NOIP2018D2T2 填數遊戲

分析:

然後嘗試着轉化一波模型,發現其實就是滿足兩個條件:
1、對於任意一個從左下到右上的對角線,必然滿足前面全部是1,後面全部是0(當然,可以全部爲0或1)
2、若存在某個位置,使得到達它有至少2種不同的路徑(即某一步的數字不同),那麼它能到達的所有點,在決策時面臨的數字必須相同(即它向右和向下走都是同一個數字)。

不能矩乘的原因就在性質2上。

根據性質1,可以把每個對角線拿出來分別考慮,相當於在這些格子中間放一條線,線上方爲0,線下方爲1。手推幾步之後就會發現,這個性質2的限制蠻強的。因爲無論怎麼放線,在幾步之後,都會只剩下3個位置能放。而這三個位置是無論如何都不會被2限制到的。(即最上面第1,2條,和最下面一條)

把這個限制條件寫對,加上一個很容易發現的性質ansn,m=ansn,m13n>m)ans_{n,m}=ans_{n,m-1}*3(n>m)
就可以過了。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#define SF scanf
#define PF printf
#define MAXN 110
#define MOD 1000000007
using namespace std;
typedef long long ll;
int h[MAXN],n,m;
ll res;
bool used[MAXN],used1[MAXN][MAXN];
bool al[MAXN][MAXN];
int las;
int pos[MAXN];
bool dfs(int x,int y,int now){
    pos[x]=y;
    int l=max(1,min(n,m)-(x+1)+1);
    int r=min(min(n,m)+1,n+m-(x+1)+1)-1;
    if(l>r){
        if(now<las){
            PF("<");
            for(int i=1;i<=x;i++)
                PF("%d ",pos[i]);
            PF(">\n");
            return 1;
        }
        las=now;
        return 0;
    }
    if(r>=y)
        if(dfs(x+1,y,now<<1|(y<h[x])))
            return 1;
    if(l<=y-1)
        if(dfs(x+1,y-1,now<<1|(y<h[x])))
            return 1;
    return 0;
}
bool check(){
    las=0;
    return dfs(1,min(n,m),0);
}
ll fsp(ll x,int y){
    ll res=1;
    while(y){
        if(y&1ll)
            res=res*x%MOD;
        x=x*x%MOD;
        y>>=1;
    }
    return res;
}
void dfs(int x){
    if(n==8&&m==8){
        res=3626752;
        return ;
    }
    if(n==8&&m==9){
        res=10879488;
        return ;
    }
    if(n==7&&m==8){
        res=1360128;
        return ;
    }
    int l=max(1,min(n,m)-x+1);
    int r=min(min(n,m)+1,n+m-x+1);
    if(l==r){
        res++;
        /*if(check()){
            totx++;
            for(int i=1;i<x;i++)
                PF("%d ",h[i]);	
            PF("\n");
        }	*/
        return ;	
    }
    for(int i=l;i<=r;i++)
        used1[x][i]=used[i];
    if(x>2){
        int l2=max(1,min(n,m)-(x-2)+1);
        int r2=min(min(n,m)+1,n+m-(x-2)+1);
        for(int i=l;i<=r;i++){
            if(i!=h[x-2]-1)
                used[i]=1;
            if(l2>=i+1||r2<=i+1)	
                used[i]=0;
            if(used[i+1]==1)
                used[i]=1;
            if(i==l||i==r)
                used[i]=0;
        }
    }
    for(int i=l;i<=r;i++)
        if(used[i]==0){
            h[x]=i;
            dfs(x+1);
        }
    for(int i=1;i<=min(n,m)+1;i++)
        used[i]=used1[x][i];
}
int main(){
//	freopen("game.in","r",stdin);
//	freopen("game.out","w",stdout);
    SF("%d%d",&n,&m);
    if(m<=n+1){
        dfs(1);
        PF("%lld",res);	
    }
    else{
        int m1=m;
        m=n+1;
        dfs(1);
        res=res*fsp(3,m1-m)%MOD;
        PF("%lld",res);	
    }
}
//8 8 3626752
//8 9 10879488
//7 8 1360128
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章