牧场的安排
M行N列牧场,1表示可种草、0表示不可;草不
正文
/*
原题:T1593 「一本通 5.4 例 2」牧场的安排 (USACO Corn Fields)
题意:M 行 N 列牧场,1 表示可种草、0 表示不可;草不能相邻(无公共边),求种植方案数 mod 10^8。
思路:按行状压。每行合法状态 s 需满足:s 只含可种草格(s&原图反码==0) 且 行内无相邻(s&(s<<1)==0)。
行转移时要求上下两行不重叠(s&t==0)。dp[当前行状态] 累加上一行所有不冲突状态。
复杂度:时间 O(M·S²),空间 O(S),S≤2^N(N≤12 时 S≤4096,实际合法状态更少)。
易错点:1) 荒废(一行都不种,s=0)也算合法状态,必须包含;
2) 取模为 10^8 而非 10^9+7;3) 输入先 M 后 N(行数×列数)。
*/
#include <bits/stdc++.h>
using namespace std;
const int MOD=100000000;
int main(){
int M,N;
if(!(cin>>M>>N)) return 0;
vector<int> fertile(M,0);
for(int i=0;i<M;i++){
int row=0;
for(int j=0;j<N;j++){
int x; cin>>x;
if(x) row|=(1<<j);
}
fertile[i]=row;
}
// 预计算每行的合法状态
vector<vector<int>> valid(M);
for(int i=0;i<M;i++){
for(int s=0;s<(1<<N);s++){
if((s&fertile[i])==s && (s&(s<<1))==0){
valid[i].push_back(s);
}
}
}
// 第 0 行:每个合法状态初始方案数为 1
vector<long long> dp;
for(int s:valid[0]) dp.push_back(1);
for(int r=1;r<M;r++){
vector<long long> ndp(valid[r].size(),0);
for(int i=0;i<(int)valid[r].size();i++){
int s=valid[r][i];
for(int j=0;j<(int)valid[r-1].size();j++){
int t=valid[r-1][j];
if((s&t)==0){
ndp[i]=(ndp[i]+dp[j])%MOD;
}
}
}
dp=move(ndp);
}
long long ans=0;
for(long long x:dp) ans=(ans+x)%MOD;
cout<<ans<<"\n";
return 0;
}
一本通·提高篇的其它内容
- 活动安排
- 种树
- 喷水装置
- 加工生产调度
- 智力大冲浪
- 数列极差
- 数列分段
- 线段
- 家庭作业
- 钓鱼
- 糖果传递
- 愤怒的牛
- Best Cow Fences
- 曲线
- 数列分段 II
- 扩散
- 灯泡
- 传送带
- 数的划分
- 生日蛋糕
- 小木棍
- Addition Chains
- 埃及分数
- 平板涂色
- 质数方阵
- 靶形数独
- 电路维修
- 魔板
- Knight Moves
- 棋盘游戏
- Keyboarding
- 移动玩具
- 山峰和山谷
- Oulipo
- 图书管理
- Power Strings
- Seekthe Name, Seek the Fame
- Friends
- A Horrible Poem
- Beads
- Antisymmetry
- 门票
- 收集雪花
- 剪花布条
- Power Strings
- Radio Transmission
- OKR-Periods of Words
- 似乎在梦中见过的样子
- Censoring
- Phone List
- The XOR Largest Pair
- Nikitosh 和异或
- Immediate Decodability
- L 语言
- Secret Message 秘密信息
- 背单词
- The Xor-longest Path
- Keywords Search
- 玄武密码
- Censoring