目录
CF438E The Child and Binary Tree
[SDOI2009]虔诚的墓主人
先离散化然后排序, 然后一列一列处理
发现两个常青树之间的那个空隙答案都是一样的, 于是可以直接上下的答案 * 中间空隙左右答案的和
即
于是考虑动态维护后面一坨, 要区间查单点修改, 于是就树状数组啦
#include<bits/stdc++.h>
#define N 500050
using namespace std;
typedef long long ll;
int read(){int x; scanf("%d", &x); return x;}
const ll Mod = 2147483648;
int n, m, w, k, b[N], siz;
ll C[N][15], ans;
int l[N], r[N];
struct Node{ int x, y;}a[N];
bool cmp(Node a, Node b){ return a.x == b.x ? a.y < b.y : a.x < b.x;}
vector<int> v[N];
ll add(ll a, ll b){ return (a+b) % Mod;}
ll mul(ll a, ll b){ return (a*b) % Mod;}
struct Bit{
ll c[N];
void Add(int x, ll val){ for(;x<=siz;x+=x&-x) c[x] = add(c[x], val);}
ll Ask(int x){ ll ans=0; for(;x;x-=x&-x) ans = add(ans, c[x]); return ans;}
}A;
int main(){
n = read(), m = read(); w = read();
for(int i=1; i<=w; i++){ a[i].x = b[++siz] = read(), a[i].y = b[++siz] = read();}
k = read();
C[0][0] = 1;
for(int i=1; i<=w; i++){
C[i][0] = 1;
for(int j=1; j<=min(i, k); j++)
C[i][j] = add(C[i-1][j], C[i-1][j-1]);
}
sort(b+1, b+siz+1); siz = unique(b+1, b+siz+1) - (b+1);
for(int i=1; i<=w; i++){
a[i].x = lower_bound(b+1, b+siz+1, a[i].x) - b;
a[i].y = lower_bound(b+1, b+siz+1, a[i].y) - b;
}
sort(a+1, a+w+1, cmp);
for(int i=1; i<=w; i++){
v[a[i].x].push_back(a[i].y); r[a[i].y]++;
}
for(int i=1; i<=siz; i++){
if(v[i].size() >= k * 2){
for(int j=0, down = 0, up = v[i].size(); j<v[i].size()-1; j++){
down++; up--;
if(down >= k && up >= k){
ans = add(ans, mul(mul(C[up][k], C[down][k]), add(A.Ask(v[i][j+1]-1), Mod-A.Ask(v[i][j]))));
}
}
}
for(int j=0; j<v[i].size(); j++){
int y = v[i][j];
l[y]++; r[y]--;
ll now = mul(C[l[y]][k], C[r[y]][k]);
ll pre = add(A.Ask(y), Mod - A.Ask(y-1));
A.Add(y, add(now, Mod-pre));
}
} printf("%lld", ans);
return 0;
}
WOJ4119 01矩阵
我们设一行和恰好为 i 的方案数为 fi
gi 为 大于等于 i 的所有情况
对于答案为 i 的方案就是
#include<bits/stdc++.h>
#define N 200050
using namespace std;
typedef long long ll;
const int Mod = 1e9 + 7;
ll add(ll a, ll b){ return (a+b) % Mod;}
ll mul(ll a, ll b){ return (a*b) % Mod;}
int n, m, x, y;
ll f[N], g[N], ans;
ll fac[N], inv[N];
ll power(ll a, ll b){
ll ans = 1; for(;b;b>>=1){
if(b&1) ans = mul(ans, a);
a = mul(a, a);
} return ans;
}
ll C(int n, int m){ return mul(fac[n], mul(inv[n-m], inv[m]));}
int main(){
scanf("%d%d%d%d", &n, &m, &x, &y);
fac[0] = fac[1] = inv[0] = inv[1] = 1;
int up = max(n, m);
for(int i=2; i<=up; i++) fac[i] = mul(fac[i-1], (ll)i);
inv[up] = power(fac[up], Mod-2);
for(int i=up-1; i>=2; i--) inv[i] = mul(inv[i+1], (ll)(i+1));
for(int i=m; i>=0; i--){
f[i] = mul(C(m, i), mul(power(x, m-i), power(y, i)));
g[i] = add(g[i+1], f[i]);
ans = add(ans, mul(i, add(power(add(g[i+1], f[i]), n), Mod-power(g[i+1], n))));
} printf("%lld", ans);
}
WOJ4096膜法
主要是学一下斐波那契的列求和
#include<bits/stdc++.h>
#define N 100050
using namespace std;
const int Mod = 1e9 + 7;
typedef long long ll;
ll fac[N], inv[N];
int n, m; ll ans = 1;
ll add(ll a, ll b){ return (a+b) % Mod;}
ll mul(ll a, ll b){ return (a*b) % Mod;}
ll C(int n, int m){ return mul(fac[n], mul(inv[n-m], inv[m]));}
ll power(ll a, ll b){
ll ans = 1; for(;b;b>>=1){
if(b&1) ans = mul(ans, a);
a = mul(a, a);
} return ans;
}
int main(){
scanf("%d%d", &n, &m);
fac[0] = fac[1] = 1; inv[0] = inv[1] = 1;
for(int i=2; i<=n+1; i++) fac[i] = mul(fac[i-1], (ll)i);
inv[n+1] = power(fac[n+1], Mod-2);
for(int i=n; i>=2; i--) inv[i] = mul(inv[i+1], i+1);
while(m--){
int l, r, k; scanf("%d%d%d", &l, &r, &k);
int x = l - k;
ll sum = add(C(r+1, x+1), Mod - C(l, x+1));
ans = mul(ans, sum);
} printf("%lld", ans); return 0;
}
BJOI2015 糖果
先把数选出来然后排序, 相当于把m个果子放到k个盘子里, 可以不放
隔板法一下就是 , 然后求它的n阶下降幂, 组合数暴力约分
#include<bits/stdc++.h>
#define N 100050
using namespace std;
typedef long long ll;
int n, m, k, p, up[N], down[N], c[N];
bool isp[N]; int prim[N], tot;
ll add(ll a, ll b){ return (a+b) % p;}
ll mul(ll a, ll b){ return (a*b) % p;}
void prework(){
for(int i=2; i<=N-50; i++){
if(!isp[i]) prim[++tot] = i;
for(int j=1; j<=tot; j++){
if(prim[j] * i > N-50) break;
isp[prim[j] * i] = 1;
if(i % prim[j] == 0) break;
}
}
}
int main(){
scanf("%d%d%d%d", &n, &m, &k, &p); prework();
for(int i=1; i<=m; i++) up[i] = m + k - i, down[i] = i;
for(int i=1; i<=tot; i++){
int x = prim[i];
for(int j=x; j<=m; j+=x)
while(down[j] % x == 0) c[i]++, down[j] /= x;
}
for(int i=1; i<=tot; i++){
int x = prim[i];
for(int j = (m+k) % x; j <= m; j+=x){
if(!j) continue;
while(c[i] && up[j] % x == 0) c[i]--, up[j] /= x;
if(c[i] == 0) break;
}
}
ll sum = 1, ans = 1;
for(int i=1; i<=m; i++) sum = mul(sum, (ll)up[i]);
for(int i=0; i<n; i++) ans = mul(ans, add((ll)sum, (ll)(p-i)));
printf("%lld", ans); return 0;
}
WOJ4163排列树
主要是儿子之间的编号不确定, 可以用组合数来分配编号
, 这里的siz[u]是已经考虑过的儿子的siz
#include<bits/stdc++.h>
#define N 100050
using namespace std;
int first[N], nxt[N<<1], to[N<<1], tot;
void add(int x, int y){
nxt[++tot] = first[x], first[x] = tot, to[tot] = y;
}
int n;
const int Mod = 998244353;
typedef long long ll;
ll f[N], siz[N], fac[N], inv[N];
ll mul(ll a, ll b){ return (a*b) % Mod;}
ll add(ll a, ll b){ return (a+b) % Mod;}
ll power(ll a, ll b){
ll ans = 1; for(;b;b>>=1){
if(b&1) ans = mul(ans, a);
a = mul(a, a);
} return ans;
}
ll C(int n, int m){ return mul(fac[n], mul(inv[n-m], inv[m]));}
void dfs(int u, int fa){
f[u] = 1;
for(int i=first[u];i;i=nxt[i]){
int t = to[i]; if(t == fa) continue;
dfs(t, u);
f[u] = mul(f[u], f[t]);
f[u] = mul(f[u], C(siz[u]+siz[t], siz[t]));
siz[u] += siz[t];
} siz[u]++;
}
int main(){
scanf("%d", &n);
fac[0] = fac[1] = inv[0] = inv[1] = 1;
for(int i=2; i<=n; i++) fac[i] = mul(fac[i-1], i);
inv[n] = power(fac[n], Mod-2);
for(int i=n-1; i>=2; i--) inv[i] = mul(inv[i+1], i+1);
for(int i=1; i<n; i++){
int x, y; scanf("%d%d", &x, &y);
add(x, y); add(y, x);
} dfs(1, 0); printf("%lld", f[1]); return 0;
}
P1350 车的放置
考虑n * m的矩形放k个车怎么做
我们可以在矩形中选k行k列然后在这个正方形中考虑
然后将整个图形分成两个矩形, 枚举上下个数就可以了
#include<bits/stdc++.h>
#define N 2050
using namespace std;
const int Mod = 100003;
typedef long long ll;
ll fac[N], inv[N], ans;
ll add(ll a, ll b){ return (a+b) % Mod;}
ll mul(ll a, ll b){ return (a*b) % Mod;}
int a, b, c, d, k;
ll power(ll a, ll b){
ll ans = 1; for(;b;b>>=1){
if(b&1) ans = mul(ans, a);
a = mul(a, a);
} return ans;
}
ll C(int n, int m){
if(n < m) return 0; if(m < 0) return 0;
return mul(fac[n], mul(inv[n-m], inv[m]));
}
ll f(int n, int m, int k){
return mul(fac[k], mul(C(n, k), C(m, k)));
}
int main(){
scanf("%d%d%d%d%d", &a, &b, &c, &d, &k);
fac[0] = fac[1] = inv[0] = inv[1] = 1;
for(int i=2; i<=N-50; i++) fac[i] = mul(fac[i-1], (ll)i);
inv[N-50] = power(fac[N-50], Mod-2);
for(int i=N-51; i>=2; i--) inv[i] = mul(inv[i+1], (ll)(i+1));
for(int i=0; i<=k; i++){
ans = add(ans, mul(f(a, b, i), f(a+c-i, d, k-i)));
} printf("%lld\n", ans); return 0;
}
[SHOI2015]超能粒子炮·改
#include<bits/stdc++.h>
#define N 2505
using namespace std;
typedef long long ll;
const int Mod = 2333;
ll C[N][N], f[N][N];
ll k, n; int T;
ll mul(ll a, ll b){ return (a*b) % Mod;}
ll add(ll a, ll b){ return (a+b) % Mod;}
ll power(ll a, ll b){
ll ans = 1; for(;b;b>>=1){
if(b&1) ans = mul(ans, a);
a = mul(a, a);
} return ans;
}
ll Lucas(ll n, ll m){
if(n < Mod && m < Mod) return C[n][m];
return mul(C[n % Mod][m % Mod], Lucas(n / Mod, m / Mod));
}
ll F(ll n, ll k){
if(k < 0) return 0; if(!n) return 1; if(!k) return 1;
if(n < Mod && k < Mod) return f[n][k];
return add( mul(F(n/Mod, k/Mod-1), f[n % Mod][Mod - 1]) , mul(Lucas(n/Mod, k/Mod), f[n % Mod][k % Mod]) );
}
int main(){
scanf("%d", &T);
C[0][0] = 1;
for(int i=1; i<=N-5; i++){
C[i][0] = 1;
for(int j=1; j<=i; j++) C[i][j] = add(C[i-1][j], C[i-1][j-1]);
}
for(int i=0; i<=N-5; i++) f[i][0] = 1;
for(int i=0; i<=N-5; i++)
for(int j=1; j<=N-5; j++)
f[i][j] = add(f[i][j-1], C[i][j]);
while(T--){
scanf("%lld%lld", &n, &k);
printf("%lld\n", F(n, k));
} return 0;
}
P4609 [FJOI2016]建筑师
首先可以将最高的作为分水岭, 左边看到A-1个, 右边看到B-1个
如果我们将一个最高的以及被它挡住的一堆建筑看做一个块, 大小为k
除了开头必须是最高的, 其它的可以随意排列, 也就是 k!, 不就是圆排列吗
我们要从n-1个中造出A+B-2个圆排列, 就是一类斯特林数S1(n-1, A+B-2)
然后从这么多个中选A-1个放在左边,
#include<bits/stdc++.h>
#define N 50050
#define M 205
using namespace std;
const int Mod = 1000000007;
typedef long long ll;
ll S[N][M], C[N][M]; int T, n, A, B;
ll add(ll a, ll b){ return (a+b) % Mod;}
ll mul(ll a, ll b){ return (a*b) % Mod;}
int main(){
C[0][0] = 1; for(int i=1; i<=M-5; i++){
C[i][0] = 1; for(int j=1; j<=i; j++) C[i][j] = add(C[i-1][j-1], C[i-1][j]);
}
S[0][0] = 1; for(int i=1; i<=N-50; i++){
for(int j=1; j<=min(i, M-5); j++) S[i][j] = add(S[i-1][j-1], mul(S[i-1][j], i-1));
}
scanf("%d", &T);
while(T--){
scanf("%d%d%d", &n, &A, &B);
printf("%lld\n", mul(C[A+B-2][A-1], S[n-1][A+B-2]));
} return 0;
}
CF932E Team Work
i^k 如何化简, 想到了二类斯特林数
n个盘子, m个球, 随意放, 枚举有多少个盘子放了就是这个
于是继续
然后就可做了, k好像可以出到1e5, 既然是5000就O(n^2)求斯特林数吧
#include<bits/stdc++.h>
#define N 5005
using namespace std;
typedef long long ll;
const int Mod = 1000000007, inv2 = (Mod+1)/2;
ll add(ll a, ll b){ return (a+b) % Mod;}
ll mul(ll a, ll b){ return (a*b) % Mod;}
ll power(ll a, ll b){ll ans=1; for(;b;b>>=1){if(b&1) ans=mul(ans, a); a=mul(a,a);} return ans;}
int n, k; ll ans, S[N][N];
int main(){
scanf("%d%d", &n, &k);
S[0][0] = 1;
for(int i=1; i<=k; i++){
for(int j=1; j<=i; j++) S[i][j] = add(mul(S[i-1][j], j), S[i-1][j-1]);
}
ll mul2 = power(2, n), pre = 1;
for(int i=0; i<=k; i++){
ans = add(ans, mul(mul2, mul(pre, S[k][i])));
mul2 = mul(mul2, inv2); pre = mul(pre, n-i);
} printf("%lld\n", ans); return 0;
}
P4091 [HEOI2016/TJOI2016]求和
前置知识
令
二项式反演
后面的等比数列一下, 然后发现后面一坨是个卷积, NTT就可以了
#include<bits/stdc++.h>
#define N 800050
using namespace std;
typedef long long ll;
const int Mod = 998244353, G = 3;
int n; ll A[N], B[N], fac[N], inv[N];
ll add(ll a, ll b){ return (a+b) % Mod;}
ll mul(ll a, ll b){ return (a*b) % Mod;}
ll power(ll a, ll b){ll ans=1; for(;b;b>>=1){if(b&1)ans=mul(ans,a); a=mul(a,a);} return ans;}
int up, bit, rev[N]; ll ans;
void Init(int len){ up = 1, bit = 0; while(up <= len) up <<= 1, bit++;
for(int i=0; i<up; i++) rev[i] = (rev[i>>1]>>1) | ((i&1) << (bit-1));
}
void NTT(ll *a, int flag){
for(int i=0; i<up; i++) if(i < rev[i]) swap(a[i], a[rev[i]]);
for(int i=1; i<up; i<<=1){
ll wn = power(G, (Mod-1)/(i<<1));
if(flag == -1) wn = power(wn, Mod-2);
for(int j=0; j<up; j+=(i<<1)){
ll w = 1;
for(int k=0; k<i; k++, w=mul(w, wn)){
ll x = a[k+j], y = mul(a[k+j+i], w);
a[k+j] = add(x, y); a[k+j+i] = add(x, Mod-y);
}
}
}
if(flag == -1){
ll inv = power(up, Mod-2);
for(int i=0; i<up; i++) a[i] = mul(a[i], inv);
}
}
int main(){
scanf("%d", &n); fac[0] = fac[1] = inv[0] = inv[1] = 1;
for(int i=2; i<=n; i++) fac[i] = mul(fac[i-1], i);
inv[n] = power(fac[n], Mod-2);
for(int i=n-1; i>=2; i--) inv[i] = mul(inv[i+1], i+1);
for(int i=0; i<=n; i++) A[i] = mul((i&1) ? Mod-1 : 1, inv[i]);
B[0] = 1; B[1] = n+1;
for(int i=2; i<=n; i++) B[i] = mul(add(power(i, n+1), Mod-1), mul(inv[i], power(i-1, Mod-2)));
Init(n*2); NTT(A, 1); NTT(B, 1);
for(int i=0; i<up; i++) A[i] = mul(A[i], B[i]);
NTT(A, -1); ll sum = 1;
for(int i=0; i<=n; i++){
ans = add(ans, mul(sum, A[i]));
sum = mul(sum, mul(i+1, 2));
} printf("%lld", ans); return 0;
}
[HAOI2018]苹果树
考虑每条边的贡献, 就是siz * (n - siz), 于是可以枚举当前点 i 和它的 siz
子树不同情况应该是结构不同或标号不同, 子树上面的情况应该是结构不同, 因为标号已经定了
首先给 i 子树分配 (siz - 1) 个标号, 从 n - i 个中选 ----
子树不同的结构有 , 因为第一个点可以接到 i 的左右儿子, 有两个选择, 第二个点有3个选择 ...
子树上面不同的结构呢 ? 首先i之前有i!种方法, i之后可以把点接在上方的点下方, 除了 i 的子树
第一次有 i-1 种接法, 第二次 i 种, 第三次 i+1种 ... (n - siz - 1) 种
于是
直接预处理 l 到 r之间的乘积
#include<bits/stdc++.h>
#define N 2050
using namespace std;
typedef long long ll;
int n, Mod;
ll C[N][N], S[N][N];
ll add(ll a, ll b){ return (a+b) % Mod;}
ll mul(ll a, ll b){ return (a*b) % Mod;}
int main(){
scanf("%d%d", &n, &Mod);
C[0][0] = 1; for(int i=1; i<=n; i++){
C[i][0] = 1; for(int j=1; j<=i; j++) C[i][j] = add(C[i-1][j-1], C[i-1][j]);
}
for(int i=1; i<=n; i++){
S[i][i] = i;
for(int j=i+1; j<=n; j++) S[i][j] = mul(S[i][j-1], j);
for(int j=0; j<i; j++) S[i][j] = 1;
}
ll ans = 0;
for(int i=2; i<=n; i++){
for(int j=1; j<=n-i+1; j++){
ans = add(ans, mul(mul(j, n-j), mul( mul(S[1][j], C[n-i][j-1]), mul(S[1][i], S[i-1][n-j-1]))));
}
} printf("%lld", ans); return 0;
}
P4841 城市规划
设 fn 为n个点的无向连通图个数
组合数很不爽, 全部除以一个 (n-1)!
多项式求逆即可
#include<bits/stdc++.h>
#define N 1000050
using namespace std;
typedef long long ll;
const int Mod = 1004535809, G = 3;
int n; ll A[N], B[N], C[N], D[N], fac[N], inv[N];
int up, bit, rev[N];
ll add(ll a, ll b){ return (a+b) % Mod;}
ll mul(ll a, ll b){ return (a*b) % Mod;}
ll power(ll a, ll b){ll ans=1; for(;b;b>>=1){if(b&1) ans=mul(ans, a); a=mul(a, a);} return ans;}
void Init(int len){ up = 1, bit = 0;
while(up <= len) up <<= 1, bit++;
for(int i=0; i<up; i++) rev[i] = (rev[i>>1]>>1)|((i&1)<<(bit-1));
}
void NTT(ll *a, int flag){
for(int i=0; i<up; i++) if(i < rev[i]) swap(a[i], a[rev[i]]);
for(int i=1; i<up; i<<=1){
ll wn = power(G, (Mod-1)/(i<<1));
if(flag == -1) wn = power(wn, Mod-2);
for(int j=0; j<up; j+=(i<<1)){
ll w = 1;
for(int k=0; k<i; k++, w=mul(w, wn)){
ll x = a[k+j], y = mul(w, a[k+j+i]);
a[k+j] = add(x, y); a[k+j+i] = add(x, Mod-y);
}
}
}
if(flag == -1){
ll inv = power(up, Mod-2);
for(int i=0; i<up; i++) a[i] = mul(a[i], inv);
}
}
void Inv(int len){
if(len == 1){ C[0] = power(B[0], Mod-2); return;}
Inv(len>>1); Init(len<<1);
for(int i=0; i<len; i++) D[i] = B[i];
for(int i=len; i<up; i++) D[i] = 0;
NTT(D, 1); NTT(C, 1);
for(int i=0; i<up; i++) C[i] = add(mul(2, C[i]), Mod-mul(D[i], mul(C[i], C[i])));
NTT(C, -1);
for(int i=len; i<up; i++) C[i] = 0;
}
int main(){
scanf("%d", &n); fac[0] = fac[1] = inv[0] = inv[1] = 1;
for(int i=2; i<=n; i++) fac[i] = mul(fac[i-1], i);
inv[n] = power(fac[n], Mod-2);
for(int i=n-1;i>=2; i--) inv[i] = mul(inv[i+1], i+1);
for(int i=1; i<=n; i++){
ll tmp = power(2, 1ll * i * (i-1) / 2);
A[i] = mul(tmp, inv[i-1]);
B[i] = mul(tmp, inv[i]);
} B[0] = 1; up = 1; while(up <= n) up <<= 1; Inv(up);
Init(n<<1); NTT(A, 1); NTT(C, 1);
for(int i=0; i<up; i++) A[i] = mul(A[i], C[i]);
NTT(A, -1); printf("%lld", mul(A[n], fac[n-1]));
return 0;
}
CF438E The Child and Binary Tree
我们不妨设一个Si, 如果出现了就为1, 否则为0
设 fi 表示权值为 n 的二叉树个数
设S的生成函数为 A, f的生成函数为F, 发现后面那一坨就是3个多项式卷起来的
发现只能取加, 然后就是多项式开根和多项式求逆
#include<bits/stdc++.h>
#define N 1000050
using namespace std;
typedef long long ll;
const int Mod = 998244353, inv2 = (Mod+1)/2;
int n, m; ll A[N], B[N], C[N], D[N], F[N], G[N], H[N];
ll add(ll a, ll b){ return (a+b) % Mod;}
ll mul(ll a, ll b){ return (a*b) % Mod;}
ll power(ll a, ll b){ll ans=1; for(;b;b>>=1){if(b&1)ans=mul(ans,a); a=mul(a,a);} return ans;}
int up, bit, rev[N];
void Init(int len){ up = 1, bit = 0;
while(up <= len) up <<= 1, bit++;
for(int i=0; i<up; i++) rev[i] = (rev[i>>1]>>1) | ((i&1) << (bit-1));
}
void NTT(ll *a, int flag){
for(int i=0; i<up; i++) if(i < rev[i]) swap(a[i], a[rev[i]]);
for(int i=1; i<up; i<<=1){
ll wn = power(3, (Mod-1)/(i<<1));
if(flag == -1) wn = power(wn, Mod-2);
for(int j=0; j<up; j+=(i<<1)){
ll w = 1;
for(int k=0; k<i; k++, w=mul(w, wn)){
ll x = a[k+j], y = mul(w, a[k+j+i]);
a[k+j] = add(x, y); a[k+j+i] = add(x, Mod-y);
}
}
}
if(flag == -1){
ll inv = power(up, Mod-2);
for(int i=0; i<up; i++) a[i] = mul(a[i], inv);
}
}
void Inv(ll *a, ll *b, int len){
if(len == 1){ b[0] = power(a[0], Mod-2); return;}
Inv(a, b, (len+1) >> 1);
Init(len << 1);
for(int i=0; i<len; i++) A[i] = a[i], B[i] = b[i];
for(int i=len; i<up; i++) A[i] = B[i] = 0;
NTT(A, 1); NTT(B, 1);
for(int i=0; i<up; i++) b[i] = add(mul(2, B[i]), Mod-mul(A[i], mul(B[i], B[i])));
NTT(b, -1);
for(int i=len; i<up; i++) b[i] = 0;
}
void Sqrt(ll *a, ll *b, int n){
b[0] = 1;
for(int len = 1; len < (n<<1); len <<= 1){
Inv(b, B, len);
Init(len << 1);
for(int i=0; i<len; i++) A[i] = a[i];
for(int i=len; i<up; i++) A[i] = 0;
NTT(A, 1); NTT(B, 1);
for(int i=0; i<up; i++) A[i] = mul(A[i], B[i]);
NTT(A, -1);
for(int i=0; i<len; i++) b[i] = mul(inv2, add(A[i], b[i]));
for(int i=len; i<up; i++) b[i] = 0;
}
}
int main(){
scanf("%d%d", &n, &m);
for(int i=1; i<=n; i++){
int x; scanf("%d", &x);
if(x <= m) F[x] = 1;
}
F[0] = 1; for(int i=1; i<=m; i++) F[i] = add(Mod, - mul(F[i], 4));
Sqrt(F, G, m+1);
G[0]++;
Inv(G, H, m+1);
for(int i=1; i<=m; i++) printf("%lld\n", mul(H[i], 2));
return 0;
}