题意:求$ \ sum_ {i = 0} ^ {n}は\ sum_ {J = 0} ^ {I} S(i、j)は2 ^ {J} J $!
実行することはできません見て...
しかし、まだの慎重な分析が必要
最も重要なステップは、変換です。
クラスの数は、第二スターリング定義されます。$ S(n、m)は$プログラムは$のN-Mに$ $ $異なる物品をセット表します
そして、その合計の内側に物事を考え、意味がセットに異なる$ $ I $ J $の記事を発見され、各セットは、属性の2種類があり、その後、これらのプログラムのセット全体が配置されている番号
したがって、この定義に基づいて、リセット状態の$ G(N)= \ sum_ {J = 0} ^ {I} S(i、j)は2 ^ {J} jは$、そこ再帰式:! $ G(N) = \ sum_ {J = 1} ^ {n}は2C_ {N} ^ {I} G(NI)$
この再帰的な列挙は、得られた素子の第1セットの起源であります
与えるために、組み合わせの数を拡大するルーチンよります
$ G(N)= \ sum_ {i = 1} ^ {n}は2 \ FRAC {N!} {I!(NI)!} G(NI)$
移調を得ることができます。
$ \ FRAC {G(N)} {N!} = \ sum_ {i = 1} ^ {N} \ FRAC {2} {I!} \ FRAC {G(NI)} {(NI)!} $
だから、右は明らかに畳み込みの形であります
设$ F(X)= \ sum_ {i = 1} ^ {N} \ FRAC {2} {I!} X ^ {I} $
$ G(X)= \ sum_ {i = 0} ^ {N} \ FRAC {G(I)} {(I)!} X ^ {I} $
この場合に直接コンボリューションの$ G(0)= 0 $を指摘、それは$ G(0)= 1 $(境界要件)が必要
したがって、それは決定することができる$ G(X)= F(x)をG(x)+ 1 $
転置得る$ G(X)= \ FRAC {1} {1-F(X)} $
(この方法は、湿分硬化のように使用することができ、FFT前記)
など、$ Gを得るために、(x)の使用は何$?
$ Iは、それぞれが!$ $のG(X)$生成機能を入手し、直接合算することができます$ $ G(x)のために、参照してください。
コードを貼り付けます。
書式#include <cstdioを> する#include <cmath> の#include <CStringの> の#include <cstdlib> 書式#include <iostreamの> の#include <アルゴリズム> 書式#include <キュー> の#include <スタック> に#define LL長い長い 使って 名前空間はstd; constの LLモード= 998244353 ; LL F [ 100005 ]。 LL FF [ 100005 ]。 G LL [ 100005 ]。 LLのINV [ 100005 ]。 [MUL LL 100005 ]。 LLのMINV [ 100005 ]。 INT [(に1 << 20)+ 5 ]。 int型のn; 無効INITを() { INV [ 0 ] = INVを[ 1 ] = MUL [ 0 ] = MUL [ 1 ] = MINV [ 0 ] = MINV [ 1 ] = 1 。 以下のために(int型 I = 2 ; iは= < 100000 ; iは++ ) { INV [I] =(モードモード/ i)は* INV [モード%I]%のモード。 MINV [I] = MINV [I- 1 ] * INV [I]%のモード。 MUL [I] = MUL [I-1 ] * I%のモード。 } } のLL pow_mul(LLのX、LLのY) { LL RET = 1 。 一方、(Y) { 場合(Y&1)RET = RET * X%のモード。 X = X * X%のモード、Y >> = 1 。 } 戻りRET。 } ボイド NTT(LL *、INT LEN、INT K) { ため(int型 I = 0を私は++; iがLEN <)であれば(私は< スワップ([I]、[I]乃至[I]に) ]); 以下のための(int型私は=1 ; iがLEN <; I << = 1 ) { LL W0 = pow_mul(3、(モード- 1)/(I << 1 ))。 用(INT J = 0 ; J <LEN; J + =(I << 1 )) { W LL = 1 。 用(INT O = 0 ; 0 <私は、O ++、W = W * W0%のモード) { LL W1 = A [J + O]、W2 = [J + O + I] * W。 [J + O] =(W1 + W2)%のモード、[J + O + I] =((W1-W2)%モード+モード)%のモード。 } } } もし(K == - 1 ) { LL INV = pow_mul(LEN、モード- 2 )。 以下のために(int型 i = 1 ; iが<(LEN >> 1); iは++)スワップ([I]、[len- I])。 以下のために(int型 iは= 0 ; iがLEN <; I ++)は、[I] [I] * INV%の= モード。 } } LL [(1 << 20)+ 5 ]、B [(1 << 20)+ 5 ]、C [(1 << 20)+ 5 ]。 空隙get_inv(LLの* fとのLL * gを、INT DEP) { 場合(DEP == 1 ) { G [ 0 ] = pow_mul(F [ 0 ]、モード- 2 )。 返します。 } INT NXT =(DEP + 1)>> 1 。 get_inv(F、G、NXT)。 INT LIM = 1、L = 0 。 一方、(LIM <= 2 * DEP)LIM << = 1、L ++ 。 以下のために(int型 i = 0 ; iは<LIM; iは++)への[I] =((の[I >> 1 ] >> 1)|((I&1)<<(1- 1 ))); 以下のために(int型 i = 0 ; I <LIM; iは++)A [I] = B [I] = 0 ; 以下のために(int型 i = 0 ; iはDEP <; iは++)A [i]は= Fの[I]。 以下のために(int型 i = 0 ; iはNXTを<; iは++)B [I] = G [i]は、 NTT(A、LIM、1)、NTT(B、LIM、1 )。 以下のために(int型 i = 0 ; I <LIM; iは++)C [I] = A [I] * B [i]は%モード* B [I]%のモード。 NTT(C、LIM、 - 1 )。 にとって(int型 i = 0 ; iはDEPを<; I ++の)グラム[I] =((2 * gの[I] -C [I])%モード+モード)%のモード。 } int型のmain() { scanf関数(" %のD "、&N) その中に(); N ++ ; 以下のために(int型 i = 1 ; iがn <; iは++)F [I] =( - 2LL * MINV [I]%モード+モード)%のモード。 F [ 0 ] = 1 。 get_inv(F、FF、N)。 LL S = 0 。 用(int型 iは= 0、S =(S + FF [I] * MUL [I]%モード)%; iがN <I ++は)モード; printf(" %LLDする\ n " 、S); リターン 0 ; }