cf 1160 E dp 组合数 思维
题意:给定一个数组,如果它含有长度>=3的回文数组,那就是不好的
问通过将数组中的 -1 用【1,k】替代,有多少种可能,使这个数组是好数组。
思路:长度>=3的回文数组,都可以转化为==3的来看,所以整个数组不含有==3的回文数组
也就是a[i]!=a[i+2] ( a[i]!=-1)
这样就可以奇偶分开来看了,将两者的组合撑起来就是答案
那么对形如 x..-1-1-1y..-1.z的序列,怎么判断可能呢?
分段来看就有4种可能: -1..-1 -1....a (a...-1) a.-1...a a..-1...b
我们对后两种dp来做,d1[N][3]有三个状态 0 :a, 1 : b, 2 非a,b
这样就有了dp的思路 了
#include<bits/stdc++.h> using namespace std; #define ll long long #define pb push_back #define mp make_pair #define fi first #define se second #define all(v) v.begin(),v.end() #define mem(a) memset(a,0,sizeof(a)) #define bug printf("get \n"); const int N = 2e5+4; const ll mod =998244353; const int INF = 1e9+4; const double eps = 1e-7; int n,k; vector<int>arr; int a[N]; ll ans1,ans2; ll d1[N][3],d2[N][2];//d1 : a....b d2 a...a ll d3[N]; ll add(ll a,ll b){ return (a+b)%mod;} ll sol(){ for(int i=0;i+1<arr.size();++i)if(arr[i]!=-1 &&arr[i]==arr[i+1])return 0; int anot=0; for(auto x:arr)if(x!=-1)anot++; if(anot==0){ ll res=k; for(int i=0;i+1<arr.size();++i){ res =res*(k-1)%mod; }return res; } //printf("??"); arr.pb(0);int las= 0; ll res=1; for(int i=0;i<arr.size();){ int num =0; while(arr[i]==-1){ num++; i++; } if(num){ //cout<<"num: " <<num<<endl; if(las==0 ||arr[i]==0){ res =res* d3[num]%mod; } else{ if(las==arr[i]) res= res * (d1[num][1]+d1[num][2])%mod; else res = res * (d1[num][0]+d1[num][2])%mod; } } las= arr[i]; i++; } //cout<<res<<endl; return res; } int main(){ cin>>n>>k; d1[1][0] = 0; d1[1][1] = 1;// d1[1][2] = k-2; d2[1][0] = 0;// d2[1][1] =k-1; d3[1] = k-1; for(int i=2;i<=n;++i){ d1[i][0] = add(d1[i-1][1],d1[i-1][2]); d1[i][1] = add(d1[i-1][0],d1[i-1][2]); //k==2??? d1[i][2] = add( add(d1[i-1][0]*(k-2),d1[i-1][1]*(k-2)) ,d1[i-1][2]*(k-3)); d2[i][0] = d2[i-1][1];// a d2[i][1] = add(d2[i-1][0]*(k-1) ,d2[i-1][1]*(k-2));//not a d3[i] = d3[i-1]*(k-1)%mod; } for(int i=1;i<=n;++i){cin>>a[i];} for(int i=1;i<=n;i+=2) arr.pb(a[i]); ans1=sol(); arr.clear(); for(int i=2;i<=n;i+=2)arr.pb(a[i]); ans2=sol(); // printf("%lld %lld \n",ans1,ans2); cout<<ans1*ans2%mod<<endl; return 0; }