[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);
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值