研究算法的都是什么天才,反正我不行
题意
给定一个
结论
按上式对一个
思路
首先,考虑合法状态
固定
初始数组:
最终数组(实例中为合法状态):
基本定义
最终状态一定是由若干 块 (一段连续的被删除的数字)组成的,就比如上例中的
且块必然由空(一段连续的未被删除的数字)隔开
简单情况
仅考虑有且仅有
若其中某个块的块的大小(块内数字个数)小于
-
最后剩余的
个待被删除的数字全在大块中:显然非法,此时这 个数正中间没有未被删除的数字,无法通过选择 的子序列删除 -
最后剩余的
个待被删除的数字既在大块也在小块中:显然非法,同上所述,无法在这 个数正中间找到未被删除的数字
若没有某个块的块的大小小于
如上图所示的
简单情况结论:合法状态当且仅当
一般情况
我们注意到简单情况结论,其等价形式即为:存在一个空,其左右块大小均大于等于
对于一般情况,对比简单情况,无非就是多了空和块
因此拓展一下:“空的左右块大小均大于等于
一般情况结论:合法状态当且仅当存在一个空,其左右待删数字个数都大于等于
对于上述结论,考虑反面“不存在空,其左右待删数字个数都大于等于
其次,考虑计算
固定删除元素的个数(设共删去
正难则反,正着直接计算合法状态情况太多易重复,考虑先计算所有最终状态,再减去非法状态
最终状态总个数:
非法状态:设
非法状态即“不存在空,其左右待删数字个数都大于等于
问题转化为将
综上得,当固定删除元素的个数(设共删去
最终对于固定
枚举
朴实无华的代码
#include<bits/stdc++.h>
using namespace std;
const int N=1e6+5,mod=998244353;
int fac[N],facinv[N];
inline int C(int a,int b){return 1ll*fac[a]*facinv[b]%mod*facinv[a-b]%mod;}
void solve()
{
int n;
cin>>n;
vector<int> ans(n,1);
for(int k=1;k<=(n-1)/2;k++)
for(int i=1;i<=n/(2*k);i++)
ans[k]+=C(n,2*k*i)-C(n-2*i*k+2*k-1,2*k-1),ans[k]%=mod;
for(int k=1;k<=(n-1)/2;k++)
cout<<(ans[k]+mod)%mod<<" \n"[k==(n-1)/2];
}
signed main()
{
std::ios::sync_with_stdio(false);
std::cin.tie(0);std::cout.tie(0);
fac[0]=1;
for(int i=1;i<=1000000;i++)
fac[i]=1ll*i*fac[i-1]%mod;
facinv[1000000]=490058372;
for(int i=999999;i>=0;i--)
facinv[i]=1ll*facinv[i+1]*(i+1)%mod;
int T=1;
cin>>T;
while(T--)
solve();
return 0;
}