傳話遊戲題解
七里香
窗外的麻雀
在電線杆上多嘴
你說這一句
很有夏天的感覺
手中的鉛筆
在紙上來來回回
我用幾行字形容你是我的誰
秋刀魚 的滋味
貓跟你都想了解
初戀的香味就這樣被我們尋回
那溫暖 的陽光
像剛摘的鮮豔草莓
你說你捨不得吃掉這一種感覺
雨下整夜
我的愛溢位就像雨水
院子落葉
跟我的思念厚厚一疊
幾句是非
也無法將我的熱情冷卻
你出現在我詩的每一頁
雨下整夜
我的愛溢位就像雨水
窗臺蝴蝶
像詩裡紛飛的美麗章節
我接著寫
把永遠愛你寫進詩的結尾
你是我唯一想要的瞭解
雨下整夜
我的愛溢位就像雨水
院子落葉
跟我的思念厚厚一疊
幾句是非
也無法將我的熱情冷卻
你出現在我詩的每一頁
那飽滿 的稻穗
幸福了這個季節
而你的臉頰像田裡熟透的番茄
你突然 對我說
七里香的名字很美
我此刻卻只想親吻你倔強的嘴
雨下整夜
我的愛溢位就像雨水
院子落葉
跟我的思念厚厚一疊
幾句是非
也無法將我的熱情冷卻
你出現在我詩的每一頁
整夜 我的愛溢位就像雨水
窗臺蝴蝶
像詩裡紛飛的美麗章節
我接著寫
把永遠愛你寫進詩的結尾
你是我唯一想要的瞭解
不是都聽了一輩子了,能不能換一首
屬於是思維極高的題,下輩子也想不到。
沒有歧義時將 \((S_1)_i\) 簡記為 \(s_i\)
首先考慮什麼時候會重複,顯然是當刪除兩個不同位置後結果一樣。
設第 \(i\) 個點被刪除的上一個時刻是 \(t_i\),也就是說在 \(S_{t_i+1}\) 時將 \(s_i\) 刪掉。
我們將貢獻同統一欽定放到後面,也就是說 \(1,2,2,1\to 1,2,1\) 我們認為是刪除後面的 \(2\),而認為刪除前面的不合法。
考慮形式化描述不合法的情況:\(s_i=s_j\land i<j\land t_i<t_j\) 並且不存在一個 \(k\) 滿足 \(i<k<j\land s_k\not=s_i\)。
容易發現這是序列不重的必要條件,感覺上也是充分的,考慮證明其充分性。
對於每個 \(S_t\) 單獨考慮,將 \(t_i>t\) 設為 \(1\),\(t_i<t\) 設為 \(0\),考慮 dp 生成子序列的過程,容易發現一個子序列和一個 \(01\) 串一一對應。
考慮統計,發現這個限制依然不太好做,發現對於一個 \(k\) 其是否滿足 \(s_k\not=s_i\) 是不重要的,因為其就算不滿足也一定可以換成 \(i,k\) 的一個判斷。
它等價於一個最小的 \(j\) 滿足 \(i<j\land t_i<t_j\),若 \(s_i=s_j\) 則不合法,這個可以在笛卡爾樹上做區間 dp。
具體的,設 \(dp_{l,r,p,v}\) 表示 \([l,r]\) 這段區間,其中填的 \(t\) 的最大值是 \(t_p=v\),轉移是顯然的,用字首和最佳化可以做到 \(nm^5\)。
考慮最佳化,發現 \(p\) 是不必要的,因為我們始終會將 \(t_p\) 和 \(t_{r+1}\) 作比較,不妨直接在列舉狀態時比較,這樣就不用在轉移時比較並記錄這一維了,於是用字首和最佳化可以做到 \(nm^3\)。
考慮幹掉 \(n\),我們最後要求的是字首和 \(sm_{1,m,n}\) 其實容易發現對於 \(n\) 只有 \(m\) 個點會變化,也就是說 \(n\) 並不在關鍵的地方,可能可以聯想到 \(sm{1,m,x}\) 是一個關於 \(x\) 的 \(m+1\) 次多項式。
證明也不難,考慮 \(sm{1,1}\) 顯然是 \(1\) 次多項式,而轉移本質是卷積,其會把次數相加。
所以用拉差差出來即可。
複雜度是 \(\mathcal{O}(m^4)\) 的,不卡常什麼的都是扯淡,關鍵的地方在於在 dp 時用 __int128_t
存值減少上界的取模(但是不要將 dp 陣列開 __int128_t
)。
Code
#include<bits/stdc++.h>
using namespace std;
using llt=long long;
using llf=long double;
using ull=unsigned long long;
#ifdef LOCAL
FILE *InFile=freopen("in_out/in.in","r",stdin),*OutFile=freopen("in_out/out.out","w",stdout);
#else
FILE *InFile=freopen("message.in","r",stdin),*OutFile=freopen("message.out","w",stdout);
#endif
const int M=207,MOD=1e9+7;
int dp[M][M][M],fac[M],ivf[M],n,m; int cs[M];
class LGG{
private: int cy[M],lmu[M],rmu[M],len;
public:
void In(){len=m+2; for(int i=1;i<=len;++i) cy[i]=dp[1][m][i];}
int operator()(int x){
int y=0; memset(lmu,0,sizeof(lmu)),memset(rmu,0,sizeof(rmu));
lmu[0]=1; for(int i=1;i<=len;++i) lmu[i]=1ll*lmu[i-1]*(x-i)%MOD;
rmu[len+1]=1; for(int i=len;i;--i) rmu[i]=1ll*rmu[i+1]*(x-i)%MOD;
for(int i=1;i<=len;++i) y=(y+1ll*cy[i]*lmu[i-1]%MOD*rmu[i+1]%MOD*ivf[i-1]%MOD*ivf[len-i]%MOD*(len-i&1?-1:1)+MOD)%MOD;
return y;
}
}Lgg;
int main(){
ios::sync_with_stdio(0),cin.tie(nullptr),cout.tie(nullptr);
cin>>n>>m; for(int i=1;i<=m;++i) cin>>cs[i];
fac[0]=1; for(int i=1;i<=M-3;++i) fac[i]=1ll*fac[i-1]*i%MOD; cerr<<fac[M-3]<<endl;
ivf[M-3]=657408467; for(int i=M-3;i;--i) ivf[i-1]=1ll*ivf[i]*i%MOD;
for(int i=1;i<=m;++i) for(int j=0;j<=m+2;++j) dp[i][i-1][j]=dp[i+1][i][j]=1;
for(int ln=1;ln<=m;++ln) for(int l=1;l+ln-1<=m;++l){
int r=l+ln-1; dp[l][r][0]=0;
for(int v=1;v<=m+2;++v){
__int128_t t=0;
for(int k=l;k<=r;++k) if(cs[k]!=cs[r+1]) t+=1ll*dp[l][k-1][v-1]*dp[k+1][r][v];
dp[l][r][v]=(t+dp[l][r][v-1])%MOD;
}
}
Lgg.In(); cout<<Lgg(n)<<endl;
}