这一周主要是先练了上周学的数位dp的模板,做了模板题熟悉几遍,然后就是看了状态dp的博客,不过说实话,这个状态dp挺难懂的,看了很长时间也不是很明白,而且这个状态dp用到很多位移运算符,虽说这样会让代码快很多,但是也导致在看某些题目的时候就会有的地方看不明白什么意思比较费劲,之前的数位dp是专门在数位上进行处理,这个状态dp当时看的时候有部分感觉有点像之前学的枚举里的子集枚举,就是用二进制来表示不同的状态,而二进制是可以代表一些很大的数的所以以此来进行状态的转移,
代表题目:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 10 + 5,M = 10 + 5;
const int P = 1e8;
int n,m;
int a[N][M],st[N];
bool g[1 << N];
int f[N][1 << N];
void solve(){
}
int main(){
scanf("%d%d", &n, &m);
for(int i = 1; i <= n; ++ i){
for(int j = 1; j <= m; ++ j){
scanf("%d", &a[i][j]);
}
}
for(int i = 1; i <= n; ++ i){
for(int j = 1; j <= m; ++ j){
st[i] = (st[i] << 1) + a[i][j];
}
}
int maxn = 1 << m;
f[0][0] = 1;
for(int i = 0; i < maxn; ++ i){
g[i] = !( i & (i << 1));
}
for(int i = 1; i <= n; ++ i){
for(int j = 0; j < maxn; ++ j){
if(g[j] && (j & st[i]) == j){///
for(int k = 0; k < maxn; ++ k){ ///
if(!(j & k)){
f[i][j] = (f[i][j] + f[i - 1][k]) % P;
}
}
}
}
}
int ans = 0;
for(int j = 0; j < maxn; ++ j){
ans = (ans + f[n][j]) % P;
}
printf("%d\n", ans);
solve();
return 0;
}
这道题题目简单容易理解,这个代码我感觉是相对容易理解的多的,而且还有许多位移运算符的几个小用法以及一些句子可以当技巧记住的。