1. 程式人生 > >CF-1140 E - Palindrome-less Arrays

CF-1140 E - Palindrome-less Arrays

ont namespace ace rom code span return include lld

題意:給定一個沒有填完的序列,數值為-1表示你可以用 1~k 中的數字去覆蓋它,求將該序列填充後,不存在長度為奇數的回文串的方案數

分析:

  1. 使之不存在長度為奇數的回文串,只需要滿足不存在長度為3的回文串即可。換句話說:\(a[i] \neq a[i+2]\) 對所有的 \(i\) 成立。可以發現 i 為奇數與 i 為偶數是互不影響的。所以可以把它劃分為兩個串

    1. 一個串由 $a_1,a_3,a_5, \dots $組成
    2. 另一個串由$ a_2,a_4,a_6,\dots$ 組成
  2. 現在問題轉化為了:給定一個序列,將其數值為-1的位置換為1~k中的數字,使得序列中兩兩相鄰數字不同的方案數。不妨換個角度想,任何一組連續的 -1(長度可以為0或1),兩邊都只有四種情況

    1. 兩邊都沒有數字(即整個串都是-1)
    2. 兩邊中有一邊沒有沒有(只有整個串的左右兩端有這種情況)
    3. 兩邊的數字相同
    4. 兩邊的數字不同

    另外我們可以發現,前兩種情況可以由後兩種情況推出來,所以只需預處理把 0~ (n/2)+1長度的-1串的方案數都預處理出來,問題就迎刃而解了。

  3. \(d(i,j)\) 表示長度為 \(i\) 的 -1 串,j 為0 表示兩邊數字相同,為1表示兩邊數字不同時的方案數,\(d[0][0] = 0, d[0][1] = 1\), 有轉移方程:

    • \(i\) 為奇數
      • \(d[i][0] = d[i/2][0]*d[i/2][0] + (k-1)*d[i/2][1]*d[i/2][1]\)
      • \(d[i][1] = d[i/2][0]*d[i/2][1]*2 + (k-2)*d[i/2][1]*d[i/2][1]\)
    • \(i\) 為偶數
      • \(d[i][0] = (k-1)*d[i-1][1]\)
      • \(d[i][1] = d[i-1][0] + (k-2)*d[i-1][1]%mod\)

對於 i 為奇數的情況,我們可以取出這個序列的中間位置 mid,當 -1 串兩端數字相同且都等於 x 時,先假設mid數字與x相同,那就轉換為了兩個長度為 i/2,序列兩端相同 的子問題,然後假設 mid 與 x不同,那麽就有(k-1)種方法,可以同樣轉換成兩個長度為 i/2 ,序列兩端不同的子問題。當 -1 串兩端數字不同時,同理。

預處理d數組之後,就可以對我們之前分好的奇偶串做處理了。思路就是記錄上一個不為-1的位置。然後最後做一下特判,就可以得到正確答案了。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod = 998244353;
ll d[100010][2];
int a[100010],b[100010];
ll n,k;
ll solve(int *a,ll len){
    ll res = 1;
    ll last = 0;
    for(ll i=1;i<=len;i++){
        if(a[i] == -1)continue;
        else{
            if(i == 1){
                last = i;continue;
            }
            if(last == 0){
                res = res * (d[i-2][0] + (k-1)*d[i-2][1])%mod;
            }
            else{
                if(a[i] == a[last]){
                    res = res * d[i-last-1][0]%mod;
                }
                else res = res * d[i-last-1][1]%mod;
            }
            last = i;
        }
    }
    if(last==0){
        res = k;
        for(int i=2;i<=len;i++)res = (res*(k-1))%mod;
    }
    else if(last !=len){
        res = res * (d[len-last-1][0] + (k-1)*d[len-last-1][1]%mod)%mod;
    }
    return res;
}
int main(){
    scanf("%lld%lld",&n,&k);
    for(int i=1;i<=n;i++){
        if(i&1)scanf("%d",&a[(i+1)/2]);
        else scanf("%d",&b[i/2]);
    }
    d[0][0] = 0;d[0][1] = 1;
    for(int i=1;i<=(n+1)/2;i++){
        if(i&1){
            int len = i/2;
            d[i][0] = (d[len][0] * d[len][0]%mod + (k-1) * d[len][1]%mod * d[len][1]%mod)%mod;
            d[i][1] = (d[len][0] * d[len][1]%mod * 2%mod + (k-2) * d[len][1]%mod * d[len][1]%mod)%mod;
        }
        else{
            d[i][0] = (d[i-1][1] * (k-1)) % mod;
            d[i][1] = (d[i-1][0] + (k-2) * d[i-1][1]%mod)%mod;
        }
    }
    printf("%lld\n",(solve(a,(n+1)/2)*solve(b,n-(n+1)/2))%mod);
    return 0;
}

CF-1140 E - Palindrome-less Arrays