ieda1
以dp[i]表示以第i个人为结尾的方案数,那么答案就是每个人结尾的总和,时间复杂度为O(n^2)
#include <bits/stdc++.h>
using namespace std;
#define accelerate ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
#define endl "\n";
#define mod 998244353
#define ll long long
#define PII pair<int,int>
#define INF 0x3f3f3f3f
const int N=2e5+10;
ll n,m,k,x,y,T;
string s[N];
ll dp[N];
bool f(string s1,string s2){
for(int i=0;i<m;i++){
if(s1[i]=='o'&&s2[i]=='o') return 0;
}
return 1;
}
int main(){
accelerate;
cin>>n>>m;
s[0]="11111111111111111";
for(int i=1;i<=n;i++) cin>>s[i];
dp[0]=1;
ll ans=0;
for(int i=1;i<=n;i++){
for(int j=0;j<=i-1;j++){
if(f(s[i],s[j])) dp[i]+=dp[j];
}
dp[i]%=mod;
ans=(ans+dp[i])%mod;
}
cout<<ans;
return 0;
}
ieda2
注意m的最大值为16,因此可以想到枚举状态,那么以dp[i]表示表示队列最后一个人的状态为i时的总方案,时间复杂度O(n*2^m)
#include <bits/stdc++.h>
using namespace std;
#define accelerate ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
#define endl "\n";
#define mod 998244353
#define ll long long
#define PII pair<int,int>
#define INF 0x3f3f3f3f
const int N=2e5+10;
ll n,m,k,x,y,T;
string s;
ll dp[N];
ll ans=0;
int main(){
accelerate;
cin>>n>>m;
ll Maxx=1<<16;
while(n--){
cin>>s;
int a=0;
for(int j=0;j<m;j++) a=(a<<1)|(s[j]=='o');
ll tmp=1;
tmp+=dp[a];
(ans+=tmp)%=mod;
// cout<<ans<<endl;
for(int j=0;j<Maxx;j++){
if(!(a&j)) (dp[j]+=tmp)%=mod;
}
}
cout<<ans;
return 0;
}
Idea3
定义f[i][j]为以一个以i为高8位,j为低8位的这样的状态为队列末尾的可行总方案,那么当我们得到一个数时,就可以枚举合格的高8位,然后加上对应的低8位的可行方案,就可以得到以该状态为末尾的方案总数,然后再枚举低8位,给对应的高8八位的dp数组加上该数的总方案,既可以更新数组,相较于Idea2,这种方案通过对每个数进行高8位的分类,使得状态之间的传递更加快捷,时间复杂度为O(2*n*2^(m/2))
#include<bits/stdc++.h>
using namespace std;
const int mod = 998244353;
int f[1 << 8][1 << 8];
//f[i][j]以i为高8位中,总以j为低8位可以放下的数
//f[i][j]表示当前队列最右边的人的状态高8位为hi
//且低8位和li没有交集的总方案数,也就是可行的
char s[17];
int main() {
int n, m; cin >> n >> m;
int ans = 0;
while (n--) {
cin >> s;
int a = 0;
for (int i = 0; i < m; ++i) {
a = (a << 1) | (s[i] == 'o');//二进制转换
}
int x = a >> 8,y = a & 255, z = 1;//高8位,低8位,
for (int i = 0; i < (1 << 8); ++i) {
if (!(x & i)) {//枚举合格的高8位中那些可以后面接上
(z += f[i][y]) %= mod;
}
}
(ans += z) %= mod;
for (int i = 0; i < (1 << 8); ++i) {
if (!(y & i)) {//枚举以ai的高8位的基础上那些低8位可以放下ai
(f[x][i] += z) %= mod;
}
}
}
cout << ans << endl;
}