#include<bits/stdc++.h>
#define cs const
using namespace std;
cs int Mod = 998244353;
int add(int a, int b){ return a + b >= Mod ? a + b - Mod: a + b;}int mul(int a, int b){ return 1ll * a * b % Mod;}int dec(int a, int b){ return a - b < 0 ? a - b + Mod: a - b;}void Add(int &a, int b){ a = add(a, b);}void Dec(int &a, int b){ a = dec(a, b);}void Mul(int &a, int b){ a = mul(a, b);}int ksm(int a, int b){ int as=1;for(;b;b>>=1,a=mul(a,a))if(b&1) as=mul(as,a); return as;}
#define poly vector<int>
#define pb push_back
cs int M = 60;
int n, p, m;
cs int K = 12;
poly w[K+1];
int bit, up, Iv; poly rev;
void Rev_init(int deg){
bit=0; up=1;while(up<deg) up<<=1,++bit; rev.resize(up); Iv=ksm(up,Mod-2);for(int i=0;i<up;i++) rev[i]=(rev[i>>1]>>1)|((i&1)<<(bit-1));}void NTT_init(){for(int i=1; i<=K; i++) w[i].resize(1<<(i-1));
int wn=ksm(3,(Mod-1)/(1<<K)); w[K][0]=1;for(int i=1; i<(1<<(K-1)); i++) w[K][i]=mul(w[K][i-1],wn);for(int i=K-1;i;i--)for(int j=0;j<(1<<(i-1));j++) w[i][j]=w[i+1][j<<1];}struct atom{
poly a[M];
void init_zero(){ a[0][0]=1;}void init_one(){for(int i=0;i<min(10,m+1);i++) ++a[i%p][i];}atom(){for(int i=0;i<p;i++) a[i].clear(),a[i].resize(m+1);}int val(int x){ return a[0][x];}};
void NTT(poly &a, int typ){for(int i=0; i<up; i++)if(i<rev[i])swap(a[i],a[rev[i]]);for(int i=1,l=1; i<up; i<<=1,++l)for(int j=0; j<up; j+=(i<<1))for(int k=0; k<i; k++){
int x=a[k+j], y=mul(w[l][k],a[k+j+i]);
a[k+j]=add(x,y); a[k+j+i]=dec(x,y);}if(typ==-1){reverse(a.begin()+1,a.end());for(int i=0;i<up;i++)Mul(a[i],Iv);}}void output(poly a){for(int i=0; i<a.size();i++)cout<<a[i]<<" ";puts("");}void NTT_trans(poly &a, int typ){ a.resize(up);NTT(a,typ);if(typ==-1) a.resize(m+1);}void inc(poly &a, poly b){ a.resize(b.size());for(int i=0; i<(int)a.size(); i++)Add(a[i],b[i]);}poly dot(poly a, poly b){for(int i=0; i<(int)a.size(); i++)Mul(a[i],b[i]); return a;}atom Mul(atom A, atom B, int deg){for(int i=0; i<p; i++) NTT_trans(A.a[i],1);for(int i=0; i<p; i++) NTT_trans(B.a[i],1);
atom C;for(int i=0; i<p; i++)for(int j=0; j<p; j++)inc(C.a[(i*deg+j)%p],dot(A.a[i],B.a[j]));for(int i=0; i<p; i++) NTT_trans(C.a[i],-1);
return C;}int main(){freopen("sum.in","r",stdin);freopen("sum.out","w",stdout);
cin >> n >> p >> m; NTT_init(); Rev_init(m+1+m);
atom A, B; A.init_one(); B.init_zero();
static int pw[M]; pw[0]=1; pw[1]=10;for(int i=2; i<=32; i++) pw[i]=pw[i-1]*pw[i-1]%p; int deg=1;for(int i=0;n;i++,n>>=1){if(n&1){ B=Mul(A,B,deg); deg=deg*pw[i+1]%p;}
A=Mul(A,A,pw[i+1]);}for(int i=0,as=0;i<=m;i++){Add(as,B.val(i)); cout<<as<<" ";} return 0;}
考慮 hall 定理,A 中任意 k 個要匹配 B 中至少 k 個,那麼我們先預處理每個數可以匹配幾個,計爲 ai,那麼合法的一個區間需要滿足 ∀i,ai≥ranki
所以我們可以用線段樹動態維護一個排名,考慮插入或刪除一個對後面的貢獻就可以了
#include<bits/stdc++.h>
#define cs const
using namespace std;
cs int N = 2e5 + 50;
cs int INF = 1e9 + 7;
template <typename T> T read(){
T cnt = 0, f = 1; char ch = 0;
while(!isdigit(ch)){ ch = getchar();if(ch == '-') f = -1;}while(isdigit(ch)) cnt = cnt*10 + (ch-'0'), ch = getchar();
return cnt * f;}int gi(){ return read<int>();}
int n, m, H, a[N], b[N];
namespace SGT{
cs int N = ::N << 2;
int mn[N], tag[N], sz[N];
#define mid ((l+r)>>1)
void build(int x, int l, int r){
mn[x] = INF;if(l == r) return;build(x<<1,l,mid);build(x<<1|1,mid+1,r);}void pushup(int x){
sz[x]=sz[x<<1]+sz[x<<1|1];
mn[x]=min(mn[x<<1],mn[x<<1|1]);}void puttag(int x, int v){ mn[x]+=v; tag[x]+=v;}void down(int x){if(tag[x])puttag(x<<1,tag[x]),puttag(x<<1|1,tag[x]),tag[x]=0;}void ins(int x, int l, int r, int p, int v){if(l==r){if(~v) ++sz[x], mn[x]=l-v;
else{ --sz[x];if(sz[x]==0) mn[x]=INF;}
return;}down(x);(p<=mid)?ins(x<<1,l,mid,p,v):ins(x<<1|1,mid+1,r,p,v);pushup(x);}void modify(int x, int l, int r, int L, int R, int v){if(L<=l&&r<=R){puttag(x,v); return;}down(x);if(L<=mid)modify(x<<1,l,mid,L,R,v);if(R>mid)modify(x<<1|1,mid+1,r,L,R,v);pushup(x);}int query(int x, int l, int r, int L, int R){if(L<=l&&r<=R) return sz[x]; int as=0;if(L<=mid) as+=query(x<<1,l,mid,L,R);if(R>mid) as+=query(x<<1|1,mid+1,r,L,R); return as;}}int main(){
n = gi(), m = gi(), H = gi();for(int i = 1; i <= m; i++) b[i] = gi();sort(b+1, b+m+1);for(int i = 1; i <= n; i++){
int x = gi();
a[i] = lower_bound(b+1, b+m+1, H-x) - b - 1;
a[i] = m - a[i];}
int as = 0;SGT::build(1,0,m);for(int i = 1; i <= n; i++){
int rk = SGT::query(1,0,m,0,a[i]);SGT::ins(1,0,m,a[i],rk);SGT::modify(1,0,m,a[i],m,-1);
if(i>m){SGT::modify(1,0,m,a[i-m],m,1);SGT::ins(1,0,m,a[i-m],-1);}if(i>=m && SGT::mn[1]>=0) ++as;} cout << as; return 0;}