牢了很久才看懂的一道题
#include<bits/stdc++.h>
#define int long long
#define fi first
#define se second
using namespace std;
const int mod=998244353;
typedef pair<int,int>pii;
const int N=3e5;
int dx[4]={1,-1,0,0};
int dy[4]={0,0,1,-1};
int num[N],inv[N];//阶乘以及阶乘的逆元
//ans=num[a]*inv[a-b]%mod*inv[b]%mod;
int kmi(int a,int b){
int res=1;
while(b){
if(b&1)res=res*a%mod;
b>>=1;
a=a*a%mod;
}
return res;
}
void init(){
num[0]=1,inv[0]=1;
for(int i=1;i<=2e5;i++){//预处理出2e5内的阶乘以及其逆元
num[i]=num[i-1]*i%mod;
inv[i]=kmi(num[i],mod-2);
}
}
/*
开始最不理解的一个点是为什么要从j(第一个不符合的位置)开始转移而不是j+1开始
反例就是对于一个i,假设我往前找一位(i-1位置)直接遇到&不等于0了
i这个位置加到这相当于对答案没影响 例如 1 2 3中的3,相当于dp[3]=dp[2],而不是dp[3]=0
所以任何一个位置最坏也能从前一个位置转移过来(直接在i前放加号)
所以j就是找的最远能放加号的位置前面的那个数
*/
void solve(){
int n;cin>>n;
vector<int>a(n+1);
vector<int>pre(n+1);
int lst=0;
for(int i=1;i<=n;i++){
cin>>a[i];
pre[i]=lst;
if(a[i]) lst=i;
}
vector<int>dp(n+1),s(n+1);//
s[0]=dp[0]=1;//考虑前0个数有1个方案数
for(int i=1;i<=n;i++){
int j=i;
int val=0;
while(j&&((val&a[j])==0)){//本质上在看最后一个加号最远能放到多前,然后前面不受第i个元素影响,既定怎么放就怎么放
val|=a[j];
j=pre[j];
}
//j现在是第一个并不进来的数或者0,加号最多能放在他后面,也就是最多能从他转移过来
if(j)dp[i]=(s[i-1]-s[j-1]+mod)%mod;//j到i-1的后面都能放加号
else dp[i]=s[i-1]-0;//0到i-1后面都能放加号
s[i]=(s[i-1]+dp[i])%mod;
}
cout<<dp[n];
}
signed main(){
ios_base::sync_with_stdio(false);
cin.tie(0),cout.tie(0);
int T=1;cin>>T;
while(T--){
solve();
cout<<endl;
}
return 0;
}

京公网安备 11010502036488号