第一次做 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);
}