列表

详情


NC232186. 第二类斯特林数·行

描述

第二类斯特林数表示把n个**不同**元素划分成m个**相同**的集合中(不能有空集)的方案数。

给定n,对于所有的整数,你要求出

由于答案会非常大,所以你的输出需要对 167772161,是一个质数) 取模。

输入描述

一行一个正整数n,意义见题目描述。
对于的数据,

输出描述

共一行个非负整数。

你需要按顺序输出的值。

示例1

输入:

3

输出:

0 1 3 1

原站题解

上次编辑到这里,代码来自缓存 点击恢复默认模板

C++(g++ 7.5.0) 解法, 执行用时: 206ms, 内存消耗: 11928K, 提交时间: 2022-09-19 12:58:11

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
const int N = 1 << 19, mod = 167772161;
ll qsm(ll a, ll b) {
    ll s = 1;
    while (b) {
        if (b & 1) s = s * a % mod;
        a = a * a % mod;
        b >>= 1;
    }
    return s;
}
void change(ll y[], int len) {
    int k;
    for (int i = 1, j = len / 2; i < len - 1; i++) {
        if (i < j) std::swap(y[i], y[j]);
        k = len / 2;
        while (j >= k) {
            j = j - k;
            k = k / 2;
        }
        if (j < k) j += k;
    }
}
// on == 1 时是 DFT,on == -1 时是 IDFT
void NTT(ll y[], int len, int on) {
    change(y, len);
    for (int h = 2; h <= len; h <<= 1) {
        ll wn = qsm(3, (mod - 1) / h);
        if (on == -1) wn = qsm(wn, mod - 2);
        for (int j = 0; j < len; j += h) {
            ll w = 1;
            for (int k = j; k < j + h / 2; k++) {
                ll u = y[k];
                ll t = w * y[k + h / 2] % mod;
                y[k] = (u + t) % mod;
                y[k + h / 2] = (u - t % mod + mod) % mod;
                w = w * wn % mod;
            }
        }
    }
    if (on == -1) {
        ll inv_n = qsm(len, mod - 2);
        for (int i = 0; i < len; i++) {
            y[i] = y[i] * inv_n % mod;
        }
    }
}
ll f[N], g[N], fac_inv[N];
int main() {
    int n;
    scanf("%d", &n);
    ll s = 1;
    fac_inv[0] = 1;
    for (int i = 1; i <= n; i++) fac_inv[i] = fac_inv[i - 1] * i % mod;
    fac_inv[n] = qsm(fac_inv[n], mod - 2);
    for (int i = n - 1; i >= 1; i--) fac_inv[i] = fac_inv[i + 1] * (i + 1) % mod;
    for (int i = 0; i <= n; i++) {
        g[i] = fac_inv[i];
        if (i & 1) g[i] = mod - g[i];
    }
    for (int i = 0; i <= n; i++) f[i] = qsm(i, n) * fac_inv[i] % mod;
    int lim = 1;
    while (lim <= 2 * n) lim <<= 1;
    NTT(f, lim, 1), NTT(g, lim, 1);
    for (int i = 0; i < lim; i++) f[i] = f[i] * g[i] % mod;
    NTT(f, lim, -1);
    for (int i = 0; i <= n; i++) {
        if (i) printf(" ");
        printf("%lld", f[i]);
    }
    return 0;
}

C++(clang++ 11.0.1) 解法, 执行用时: 175ms, 内存消耗: 21776K, 提交时间: 2023-08-11 12:30:21

#include<bits/stdc++.h>
#define int long long
#define For(i,a,b) for(i=a;i<=b;i++)
#define FOR(i,a,b) for(i=a;i>=b;i--)
using namespace std;
const int N=6e5+10,mod=167772161,G=3;
int a[N],b[N],g[N];
int rev[N];
int fac[N],inv[N];
int qz(int x,int y){
	int res=1;
	for(;y;y>>=1){
		if(y&1) res=res*x%mod;
		x=x*x%mod;
	}
	return res;
}
void init(int n){
	int i;
	fac[0]=1;
	For(i,1,n) fac[i]=fac[i-1]*i%mod;
	inv[n]=qz(fac[n],mod-2);
	FOR(i,n-1,0) inv[i]=inv[i+1]*(i+1)%mod;
}
void ntt(int a[],int sign,int tot){
	int i,j,mid;
	For(i,0,tot-1) if(i<rev[i]) swap(a[i],a[rev[i]]);
	int inv_G=qz(G,mod-2);
	for(mid=1;mid<tot;mid<<=1){
		auto g1=qz(G,(mod-1)/(mid<<1));
		if(sign==-1) g1=qz(inv_G,(mod-1)/(mid<<1));
		for(i=0;i<tot;i+=(mid<<1)){
			auto gk=1; 
			for(j=0;j<mid;j++,gk=gk*g1%mod){
				auto x=a[i+j],y=gk*a[i+j+mid]%mod;
				a[i+j]=(x+y)%mod,a[i+j+mid]=(x-y+mod)%mod;
			}
		}
	}
	int inv=qz(tot,mod-2);
	if(sign==-1) For(i,0,tot-1) a[i]=a[i]*inv%mod;
}
void mul(int a[],int n,int b[],int m,int c[]){
	int i,tot=0,bit=0;
	while((1<<bit)<=n+m) bit++;
	tot=1<<bit;
	For(i,0,tot-1) rev[i]=(rev[i>>1]>>1)|((i&1)<<(bit-1));
	ntt(a,1,tot),ntt(b,1,tot);
	For(i,0,tot-1) c[i]=a[i]*b[i]%mod;
	ntt(c,-1,tot);
}
signed main(){
	init(2e5);
	int i,n;
	cin>>n;
	For(i,0,n){
		if(i&1) a[i]=-inv[i];
		else a[i]=inv[i];
	}
	For(i,0,n) b[i]=qz(i,n)*inv[i]%mod;
	mul(a,n+1,b,n+1,g);
	For(i,0,n) cout<<g[i]<<' ';
	cout<<'\n';
	return 0;
}

上一题