题面
题解
首先题意可以转化为:给你一个长度为 n n n 的序列 c c c,求将 c c c 分成两个长度为 n 2 \dfrac{n}{2} 2n 的相同的子序列的方案数。
考虑 dp,设
f
(
i
,
s
t
a
)
f(i,sta)
f(i,sta) 表示已经将
c
c
c 的前
i
i
i 位分成了两个子序列,其中长的子序列比短的子序列多出来的未匹配的部分为
s
t
a
sta
sta(用 deque
、list
等STL容器均可记录)的方案数。不妨称这个
s
t
a
sta
sta 为状态,那么只有当状态长度不大于
n
2
\dfrac{n}{2}
2n 时,这个状态才是有用的。
转移十分简单:新加入一个元素时,考虑是继续扔到当前状态的尾部,还是和当前状态的开头匹配并删除这个开头。
这里主要讲为什么时间是对的:
时间复杂度和状态数有关。假设当前到第 i i i 位,一共有 x x x 个状态,考虑接下来的 c c c 的两个元素 a , b a,b a,b:
- 如果他们相等,那么 “ a a a 删开头扔尾部” 和 “ b b b 删开头扔尾部” 得到的状态一样,所以新状态共 3 x 3x 3x 种。
- 如果他们不相等,那么 “ a a a 删开头扔尾部” 和 “ b b b 删开头扔尾部” 两种中仅有一种是可行的,否则他们相等,矛盾。所以新状态共 3 x 3x 3x 种。
于是此时总状态不超过 3 n 2 3^{\tfrac{n}{2}} 32n 种。但还是太多了。
由于我们只需要知道 f ( n , ∅ ) f(n,\empty) f(n,∅),所以考虑折半:将 c c c 序列的前一半和后一半(要翻转)分别 dp,最后将前后两半的 dp 值合并起来统计答案。
此时状态数不超过 3 n 4 3^{\tfrac{n}{4}} 34n 种。
然后题解说进一步分析(?)可以证明在 n = 60 n=60 n=60 时状态数不超过 50000 50000 50000。
代码如下:
#include<bits/stdc++.h>
#define N 65
using namespace std;
namespace modular
{
const int mod=998244353;
const int inv2=499122177;
inline int add(int x,int y){return x+y>=mod?x+y-mod:x+y;}
inline int dec(int x,int y){return x-y<0?x-y+mod:x-y;}
inline int mul(int x,int y){return 1ll*x*y%mod;}
}using namespace modular;
inline int read()
{
int x=0,f=1;
char ch=getchar();
while(ch<'0'||ch>'9')
{
if(ch=='-') f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9')
{
x=(x<<1)+(x<<3)+(ch^'0');
ch=getchar();
}
return x*f;
}
typedef deque<int> STA;
int T,n,hn,a[N];
STA now1,now2;
map<STA,int>dp[2][N>>1];
void solve(bool opt)
{
for(int i=0;i<=hn;i++) dp[opt][i].clear();
now1.clear();
dp[opt][0][now1]=1;
for(int i=0;i<hn;i++)
{
for(map<STA,int>::iterator it=dp[opt][i].begin();it!=dp[opt][i].end();it++)
{
now1=(*it).first;
if((!now1.empty())&&now1.front()==a[i+1])
{
now2=now1;
now2.pop_front();
dp[opt][i+1][now2]=add(dp[opt][i+1][now2],dp[opt][i][now1]);
}
now2=now1;
now2.push_back(a[i+1]);
if(!now1.empty()) dp[opt][i+1][now2]=add(dp[opt][i+1][now2],dp[opt][i][now1]);
else dp[opt][i+1][now2]=add(dp[opt][i+1][now2],mul(dp[opt][i][now1],2));
}
}
}
int main()
{
T=read();
while(T--)
{
n=read();
hn=n>>1;
for(int i=1;i<=n;i++) a[i]=read();
solve(0);
reverse(a+1,a+n+1);
solve(1);
int ans=0;
for(map<STA,int>::iterator it=dp[0][hn].begin();it!=dp[0][hn].end();it++)
{
now1=(*it).first;
while(!now2.empty()) now2.pop_front();
while(!now1.empty())
{
now2.push_back(now1.back());
now1.pop_back();
}
if(!now2.empty()) ans=add(ans,mul((*it).second,mul(dp[1][hn][now2],inv2)));
else ans=add(ans,mul((*it).second,dp[1][hn][now2]));
}
printf("%d\n",ans);
}
return 0;
}
/*
5
2
1 1
2
2 2
4
1 1 2 2
6
1 2 3 4 5 6
4
1 2 2 1
*/
实测 deque
比 list
快,我直接疑惑了。