[jzoj4197]兔子走路

第一次做 NOI 難度 嚇得我都不敢放傳送門
(っ °Д °;)っ

Solution

可以發現,兔子間互相獨立。

因而,結果最多隻和兩隻兔子有關。

正難則反 考慮不合法的情況

可以用記憶化搜索或一類算法 處理出和某個位置不能同時出現的位置

最後注意避免重複即可

數據水到可以 O(1)

Code

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
using namespace std;
#define maxn 43
#define maxm 1700
char s[maxn][maxn];
int id[maxn][maxn],pos[maxm][maxm],num,cnt;
bool map[maxm][maxm];
struct edges{
    int to,next;
}edge[maxm*maxm*4];
int next[maxm*maxm],l;
inline void addedge(int x,int y){
    edge[++l]=(edges){y,next[x]};next[x]=l;
}
int a[maxm],ans;
void dfs(int x,int sum=0) {
    if (x==cnt) {ans--;return ;}
    for (int i=1;i<=sum;i++) {
    if (map[x][a[i]]==1) return dfs(x+1,sum);
    }
    dfs(x+1,sum);
    a[++sum]=x;
    dfs(x+1,sum);
}
#define mod 1000000007
inline int power(int x,int y) {
    int ans=1;
    for (;y;y>>=1) {
    if (y&1) ans=ans*1ll*x%mod;
    x=x*1ll*x%mod;
    }
    return ans;
}
int w[4][2]={{1,0},{0,1},{-1,0},{0,-1}};
int main(){
    freopen("board.in","r",stdin);
    freopen("board.out","w",stdout);
    int n,m;
    scanf("%d%d",&n,&m);
    for (int i=1;i<=n;i++) scanf("%s",s[i]+1);
    for (int i=1;i<=n;i++) 
    for (int j=1;j<=m;j++) if (s[i][j]=='0') id[i][j]=++cnt;
    cnt++;
    for (int i=1;i<=n;i++) id[i][0]=id[i][m+1]=cnt;
    for (int i=1;i<=m;i++) id[0][i]=id[n+1][i]=cnt;
    static int q[maxm*maxm];
    static bool b[maxm*maxm];
    int r=0;
    for (int i=1;i<=cnt;i++)
    for (int j=1;j<=cnt;j++) {
        if (i==j) continue;
        pos[i][j]=++num;
        if (i==cnt||j==cnt) {
        q[++r]=num;
        b[num]=1;
        }
    }
    for (int i=1;i<=n;i++) 
    for (int j=1;j<=m;j++) 
        for (int k=1;k<=n;k++) 
        for (int l=1;l<=m;l++) {
            if (!pos[id[i][j]][id[k][l]]) continue;
            for (int z=0;z<4;z++) {
            int x=id[i+w[z][0]][j+w[z][1]],y=id[k+w[z][0]][k+w[z][1]];
            if (!x) x=id[i][j];
            if (!y) y=id[k][l];
            if (x==id[i][j]&&y==id[k][l]) continue;
            if (x==y) continue;
            addedge(pos[x][y],pos[id[i][j]][id[k][l]]);
            }
        }
    for (int l=1,u=q[l];l<=r;u=q[++l]) 
    for (int i=next[u];i;i=edge[i].next) {
        if (b[edge[i].to]) continue;
        b[edge[i].to]=1;
        q[++r]=edge[i].to;
    }
    for (int i=1;i<=n;i++) 
    for (int j=1;j<=m;j++) 
        for (int k=1;k<=n;k++) 
        for (int l=1;l<=m;l++) {
            int t=pos[id[i][j]][id[k][l]];
            if (!b[t]) continue;
            map[id[i][j]][id[k][l]]=map[id[k][l]][id[i][j]]=1;
        }
    ans=power(2,cnt-1);
    dfs(1);
    printf("%d\n",(ans+mod)%mod);
    return 0;
}

O(1) 做法 手動滑稽

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define oo 2139062143
#define fo(i,x,y) for (register int i = (x);i <= (y);++ i)
#define fd(i,x,y) for (register int i = (x);i >= (y);-- i)
using namespace std;
typedef double db;
typedef long long ll;
int abs(int x) {return(((x)>=0)?(x):(-(x)));}
int max(int x,int y) {return(((x)>(y))?(x):(y));}
int min(int x,int y) {return(((x)<(y))?(x):(y));}
int lowbit(int x) {return((x)&(-x));}
const int N = 5,M = 5,Mo = 1e9 + 7;
int n,m,all,za;
ll ans = 0;
int main()
{
    freopen("board.in","r",stdin);
    freopen("board.out","w",stdout);
    scanf("%d%d", &n, &m);
    ans = 0;
    fo(i,1,n) fo(j,1,m)
    {
        char c = ' ';
        while (c != '0' && c != '1') c = getchar();
        if (c == '0') ++ ans;
    }
    ll p = 1;
    fo(i,1,ans) p = (p * 2) % Mo;
    p = (p + Mo - 1 - ans) % Mo;
    printf("%lld", p);
}
發佈了162 篇原創文章 · 獲贊 297 · 訪問量 16萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章