2..3...4.... Wonderful! Wonderful! 题解

2..3...4.... Wonderful! Wonderful!

题目描述

​ 有一个元素等于其下标的数组,长度为n,对于属于区间\([1,(n-1)/2]\)的每一个数,我们称其为k,我们可以对数组进行任意次数的操作。

​ 操作:选择长度为\(2*k+1\)的子序列,然后只留下最中间的那个数,删掉其他的元素。

​ 我们想知道对于每个\(k\),操作后,最后有多少个可能得到的数组。

数据范围

\(t\)组数据,每组就一个\(n\),$n $的总和不大于\(1e6\)

解法

​ 我们设x为总共要删掉的数量,会发现最后能得到的数组,有以下特征。

​ 1,x为\(2k\)的倍数,这一点显然。

​ 2,存在一个元素,它的两边有至少k个要删掉的元素。

​ 我们证明以下,对于2中存在的元素,我们看他的两边,如果一两边的数量大于k,我们就一定能选择一个元素作为删除操作中的中心元素,然后成功删掉大于k的部分元素。过了一段时间后,就会出现只剩下\(2k\)个元素的情况,然后就能一次删掉了。

​ 搞清楚以上的局面,我们需要再发现,正面求出这些还是很困难的,于是我们求出总数\(C(n,x)\)后,再减去不合法的即可。需要注意的是, x是要枚举的,但x为2k的倍数,所以其复杂度为调和级数。

​ 现在我们先将要删掉的元素排成一排,然后往里面插入那些不删掉的。想要不合法,全向左右两边的\(k-1\)个元素扎入即可。于是问题就转化成了有n-x个相同的小球,要插入2k个相同盒子,允许盒子有空的,问有多少种情况。答案就是\(C(n-x+2*k-1,2*k-1)\)。这里为什么小球和盒子都是相同的呢?因为元素的顺序是已经定下的。

代码实现

const int mod=998244353;
const int maxn=1000010;
int fect[maxn], infect[maxn];
ll binpow(ll a,ll b,ll c){
    ll ans=1;
    while(b){
        if(b&1)
        ans=(Int)ans*a%c;
        a=(Int)a*a%c;
        b>>=1;
    }
    return ans;
}
int C(int a,int b){
    return fect[a]*infect[b]%mod*infect[a-b]%mod;
}
void initzuhe(int n){
    fect[0]=1;
    infect[0]=1;
    for(int i=1;i<=n;i++){
        fect[i]=(fect[i-1]*i)%mod;
    }
    infect[n]=binpow(fect[n],mod-2,mod);
    for(int i=n-1;i>=1;i--)
    infect[i]=infect[i+1]*(i+1)%mod;
}
ll cul(int n,int k){
    ll ans=0;
    for(int x=2ll*k;x<=n;x+=2ll*k){
        ans=(ans+C(n,x)-C(n-x-1+2ll*k,2ll*k-1)+mod)%mod;
    }
    return ans;
}
void solve(){
    int n;cin>>n;
    for(int k=1;k<=(n-1)/2ll;k++)cout<<(cul(n,k)+1ll)%mod<<" ";
    cout<<"\n";
}
signed main(){
    std::ios::sync_with_stdio(false);std::cin.tie(0);std::cout.tie(0);
    initzuhe(1000000);
    //srand((unsigned)time(NULL));
    int t;std::cin>>t;while(t--)
    solve();
}
posted @ 2024-02-26 18:02  magic_here_tonight  阅读(20)  评论(0)    收藏  举报