算法模板
数据结构
FHQ-Treap
int Q;
mt19937 seed(time(0));
uniform_int_distribution<int> rnd(0,2e9);
struct FHQTreap{
int lc,rc;
int key,num;
int siz;
}tr[N];
int tot,root;
int NewNode(int x){
tr[++tot]={0,0,x,rnd(seed),1};
return tot;
}
void Pushup(int p){
tr[p].siz=tr[tr[p].lc].siz+tr[tr[p].rc].siz+1;
}
void Buildtr(){
NewNode(-IINF); NewNode(IINF);
tr[1].rc=2; root=1;
if(tr[1].num<tr[2].num)
swap(tr[1].num,tr[2].num);
Pushup(1);
}
void Split(int p,int v,int &L,int &R){
if(!p) return L=R=0,void();
if(tr[p].key<=v)
L=p,Split(tr[p].rc,v,tr[p].rc,R);
else R=p,Split(tr[p].lc,v,L,tr[p].lc);
Pushup(p);
}
int Merge(int p,int q){
if(!p) return q;
if(!q) return p;
if(tr[p].num<tr[q].num){
tr[q].lc=Merge(p,tr[q].lc);
Pushup(q); return q;
}
else{
tr[p].rc=Merge(tr[p].rc,q);
Pushup(p); return p;
}
}
void Insert(int x){
int L,R,p=NewNode(x);
Split(root,x,L,R);
root=Merge(Merge(L,p),R);
}
void Delete(int x){
int L,R,P;
Split(root,x-1,L,R);
Split(R,x,P,R);
P=Merge(tr[P].lc,tr[P].rc);
root=Merge(Merge(L,P),R);
}
int AskVal(int p,int k){
if(!p) return -IINF;
if(tr[tr[p].lc].siz>=k) return AskVal(tr[p].lc,k);
else if(tr[tr[p].lc].siz+1==k) return tr[p].key;
else return AskVal(tr[p].rc,k-tr[tr[p].lc].siz-1);
}
int AskRank(int x){
int L,R,res;
Split(root,x-1,L,R);
res=tr[L].siz;
root=Merge(L,R);
return res;
}
int AskPre(int x){
int L,R;
Split(root,x-1,L,R);
int res=AskVal(L,tr[L].siz);
root=Merge(L,R);
return res;
}
int AskNxt(int x){
int L,R;
Split(root,x,L,R);
int res=AskVal(R,1);
root=Merge(L,R);
return res;
}
signed main(){
read(Q);
Buildtr();
while(Q--){
int op,x;
read(op),read(x);
if(op==1) Insert(x);
else if(op==2) Delete(x);
else if(op==3) printf("%d\n",AskRank(x));
else if(op==4) printf("%d\n",AskVal(root,x+1));
else if(op==5) printf("%d\n",AskPre(x));
else printf("%d\n",AskNxt(x));
}
return 0;
}
Splay
int Q,root,tot;
struct SplayTree{
int s[2],fa;
int key,cnt,siz;
#define lc s[0]
#define rc s[1]
}tr[N];
int NewNode(int v){
tr[++tot]={{0,0},0,v,1,1};
return tot;
}
void Pushup(int p){
tr[p].siz=tr[tr[p].lc].siz+tr[tr[p].rc].siz+tr[p].cnt;
}
int Dir(int p){return tr[tr[p].fa].s[1]==p;}
void Rotate(int x){
int y=tr[x].fa,z=tr[y].fa,c=Dir(x);
tr[y].s[c]=tr[x].s[c^1];
if(tr[x].s[c^1]) tr[tr[x].s[c^1]].fa=y;
tr[x].s[c^1]=y; tr[y].fa=x; tr[x].fa=z;
if(z) tr[z].s[y==tr[z].s[1]]=x;
Pushup(y); Pushup(x);
}
void Splay(int x){
while(tr[x].fa){
int y=tr[x].fa;
if(tr[y].fa){
if(Dir(y)==Dir(x)) Rotate(y);
else Rotate(x);
}
Rotate(x);
}
root=x;
}
void Insert(int v){
int p=root,q=0;
while(p){
q=p;
if(v<tr[p].key) p=tr[p].lc;
else if(tr[p].key==v) break;
else p=tr[p].rc;
}
// printf("Insert: P=%d,Q=%d\n",p,q);
if(p) tr[p].cnt++,tr[p].siz++;
else{
p=NewNode(v); tr[p].fa=q;
tr[q].s[v>tr[q].key]=p;
}
Splay(p);
}
void Delete(int v){
int p=root,q=0;
while(p){
q=p;
if(v==tr[p].key) break;
else if(v<tr[p].key) p=tr[p].lc;
else p=tr[p].rc;
}
Splay(p);
if(tr[p].cnt>1){
tr[p].cnt--;
tr[p].siz--;
return;
}
if(!tr[p].lc){
tr[tr[p].rc].fa=0;
root=tr[p].rc;
return;
}
q=tr[p].lc;
while(tr[q].rc) q=tr[q].rc;
tr[q].rc=tr[p].rc; tr[tr[p].rc].fa=q;
tr[tr[p].lc].fa=0; root=tr[p].lc;
Splay(q);
}
int AskPre(int v){
int p=root,q=0,res=-IINF;
while(p){
q=p;
if(tr[p].key<v) res=tr[p].key,p=tr[p].rc;
else p=tr[p].lc;
}
Splay(q); return res;
}
int AskNxt(int v){
int p=root,q=0,res=IINF;
while(p){
q=p;
if(tr[p].key>v) res=tr[p].key,p=tr[p].lc;
else p=tr[p].rc;
}
Splay(q); return res;
}
int AskRank(int v){
int p=root,q=0,res=0;
while(p){
q=p;
if(tr[p].key<v) res+=tr[tr[p].lc].siz+tr[p].cnt,p=tr[p].rc;
else p=tr[p].lc;
}
Splay(q); return res+1;
}
int AskVal(int k){
int p=root,q=0,res=0;
while(p){
q=p;
if(tr[tr[p].lc].siz>=k) p=tr[p].lc;
else if(tr[tr[p].lc].siz+tr[p].cnt>=k){res=tr[p].key;break;}
else k-=tr[tr[p].lc].siz+tr[p].cnt,p=tr[p].rc;
}
Splay(q); return res;
}
void Output(int x){
if(!x) return puts("Empty"),void();
printf("Tr[%d]: fa=%d,lc=%d,rc=%d,key=%d,siz=%d\n",x,tr[x].fa,tr[x].lc,tr[x].rc,tr[x].key,tr[x].siz);
}
void Print(int p,string s,bool fir){
cout<<s<<(fir?"+---":"\\---");
Output(p);
if(!p) return;
s+=fir?"| ":" ";
Print(tr[p].lc,s,1);
Print(tr[p].rc,s,0);
}
signed main(){
read(Q);
while(Q--){
int op,x;
read(op),read(x);
if(op==1) Insert(x);
else if(op==2) Delete(x);
else if(op==3) printf("%d\n",AskRank(x));
else if(op==4) printf("%d\n",AskVal(x));
else if(op==5) printf("%d\n",AskPre(x));
else printf("%d\n",AskNxt(x));
// Print(root,"",1);
}
return 0;
}
字符串
KMP
char a[N],b[N];
int nxt[N],j,n,m;
vector<int> pos;
signed main() {
scanf("%s",a+1);
scanf("%s",b+1);
n=strlen(a+1);
m=strlen(b+1);
for(int i=2;i<=m;i++){
while(j>0&&b[i]!=b[j+1]) j=nxt[j];
if(b[i]==b[j+1]) j++;
nxt[i]=j;
}
j=0;
for(int i=1;i<=n;i++){
while(j>0&&(j==n||a[i]!=b[j+1])) j=nxt[j];
if(a[i]==b[j+1]) j++;
if(j==m) pos.push_back(i-j+1);
}
for(int i=0;i<pos.size();i++){
cout<<pos[i]<<endl;
}
for(int i=1;i<=m;i++){
cout<<nxt[i]<<" ";
}
cout<<endl;
return 0;
}
ExKMP / Algorithm Z
int n,m;
char a[N],b[N];
int z[N],ext[N];
void ExKMP(){
for(int i=2,k=1;i<=m;i++){
if(k+z[k]-1>=i) z[i]=min(z[i-k+1],k+z[k]-i);
while(i+z[i]<=m&&b[i+z[i]]==b[z[i]+1]) z[i]++;
if(i+z[i]>k+z[k]) k=i;
}
for(int i=1,k=0;i<=n;i++){
if(k+ext[k]-1>=i) ext[i]=min(z[i-k+1],k+ext[k]-i);
while(ext[i]<m&&i+ext[i]<=n&&a[i+ext[i]]==b[ext[i]+1]) ext[i]++;
if(i+ext[i]>k+ext[k]) k=i;
}
z[1]=m;
}
ACAM
int n;
string s[N],t;
int ed[N],tot=1;
struct Trie{
int son[29];
int fail,cnt,in;
}tr[N];
void Insert(string x,int id){
int len=x.length(),p=1;
for(int i=0;i<len;i++){
int c=x[i]-'a';
if(!tr[p].son[c])
tr[p].son[c]=++tot;
p=tr[p].son[c];
}
ed[id]=p;
}
void BuildAC(){
queue<int> q;
for(int i=0;i<26;i++)
tr[0].son[i]=1;
tr[1].fail=0;
q.push(1);
while(q.size()){
int p=q.front();
// printf("Tr[%d].Fail=%d\n",p,tr[p].fail);
q.pop();
for(int i=0;i<26;i++){
if(!tr[p].son[i])
tr[p].son[i]=tr[tr[p].fail].son[i];
else{
tr[tr[p].son[i]].fail=tr[tr[p].fail].son[i];
q.push(tr[p].son[i]);
}
}
}
for(int i=1;i<=tot;i++){
tr[tr[i].fail].in++;
// printf("Tr[%d].fail=%d\n",i,tr[i].fail);
}
}
void Query(){
int p=1,len=t.length();
for(int i=0;i<len;i++){
int c=t[i]-'a';
p=tr[p].son[c];
tr[p].cnt++;
}
}
void TopoSort(){
queue<int> q;
for(int i=1;i<=tot;i++){
if(!tr[i].in)
q.push(i);
}
while(q.size()){
int x=q.front();
q.pop();
int y=tr[x].fail;
tr[y].cnt+=tr[x].cnt;
if(!(--tr[y].in))
q.push(y);
}
}
signed main(){
read(n);
for(int i=1;i<=n;i++){
cin>>s[i];
Insert(s[i],i);
}
cin>>t;
BuildAC();
Query();
TopoSort();
for(int i=1;i<=n;i++) printf("%d\n",tr[ed[i]].cnt);
return 0;
}
SA
int n,m;
char a[N];
int rk[N],tp[N],sa[N],c[N];
#define V(x) min((x),n+1)
signed main(){
scanf("%s",a+1);
n=strlen(a+1);
m='z';
for(int i=1;i<=n;i++)
rk[i]=a[i],c[rk[i]]++;
for(int i=1;i<=m;i++) c[i]+=c[i-1];
for(int i=n;i;i--) sa[c[rk[i]]--]=i;
for(int k=1;k<=n;k<<=1){
int p=0;
for(int i=n-k+1;i<=n;i++) tp[++p]=i;
for(int i=1;i<=n;i++)
if(sa[i]>k) tp[++p]=sa[i]-k;
for(int i=1;i<=m;i++) c[i]=0;
for(int i=1;i<=n;i++) c[rk[i]]++;
for(int i=1;i<=m;i++) c[i]+=c[i-1];
for(int i=n;i;i--) sa[c[rk[tp[i]]]--]=tp[i];
memcpy(tp,rk,sizeof(tp));
rk[sa[1]]=m=1;
for(int i=2;i<=n;i++){
if(tp[sa[i]]==tp[sa[i-1]]&&tp[V(sa[i]+k)]==tp[V(sa[i-1]+k)]) rk[sa[i]]=m;
else rk[sa[i]]=++m;
}
if(m==n) break;
}
for(int i=1;i<=n;i++) printf("%d ",sa[i]);
return 0;
}
SAM
int n;
char a[N];
struct SAM{
int tr[26];
int len,lnk,siz;
}sam[N];
int tot=1,lst=1;
vector<int> e[N];
void Insert(int c){
int p=++tot,q=lst;
sam[p].len=sam[q].len+1;
for(;q&&!sam[q].tr[c];q=sam[q].lnk) sam[q].tr[c]=p;
if(!q) sam[p].lnk=1;
else{
int z=sam[q].tr[c];
if(sam[q].len+1==sam[z].len) sam[p].lnk=z;
else{
int up=++tot,dn=z;
sam[up]=sam[dn],sam[up].len=sam[q].len+1;
for(;q&&sam[q].tr[c]==dn;q=sam[q].lnk) sam[q].tr[c]=up;
sam[dn].lnk=sam[p].lnk=up;
}
}
lst=p;
}
void dfs(int x){
for(int y:e[x]){
dfs(y);
sam[x].siz+=sam[y].siz;
}
}
signed main(){
scanf("%s",a+1);
n=strlen(a+1);
for(int i=1;i<=n;i++) Insert(a[i]-'a');
for(int i=1;i<=tot;i++){
e[sam[i].lnk].push_back(i);
// for(int j=0;j<26;j++) if(sam[i].tr[j]) printf("Trans[%d,%d]=%d\n",i,j,sam[i].tr[j]);
// printf("Lnk[%d]=%d,Siz[%d]=%d\n",i,sam[i].lnk,i,sam[i].siz);
}
dfs(1);
ll ans=0;
for(int i=1;i<=tot;i++)
if(sam[i].siz>1) Ckmax(ans,1ll*sam[i].siz*sam[i].len);
printf("%lld\n",ans);
return 0;
}
后缀树 Ukkonen
int n,m;
char a[N];
int tot=1,now=1,rem=0;
int dep[M],siz[M];
int trie[M][27],len[M],st[M],lnk[M];
ll ans;
int Create(int s,int l){
++tot;
st[tot]=s,len[tot]=l;
return tot;
}
void Ukkonen(int x){
// printf("Ukkonen(%d)\n",x);
++rem; ++m;
for(int lst=1;rem;){
while(len[trie[now][a[m-rem+1]-'a']]<rem){
rem-=len[now=trie[now][a[m-rem+1]-'a']];
}
int &u=trie[now][a[m-rem+1]-'a'];
int c=a[st[u]+rem-1]-'a';
if(!u){
u=Create(m,IINF);
lst=lnk[lst]=now;
}
else if(c==x){
lst=lnk[lst]=now;
break;
}
else{
int v=Create(st[u],rem-1);
trie[v][c]=u,trie[v][x]=Create(m,IINF);
st[u]+=rem-1,len[u]-=rem-1;
lst=lnk[lst]=u=v;
}
if(now==1) --rem;
else now=lnk[now];
}
}
void dfs(int x){
int cs=0;
for(int i=0;i<=26;i++)
if(trie[x][i]){
++cs;
int y=trie[x][i];
dep[y]=dep[x]+len[y];
dfs(y); siz[x]+=siz[y];
}
if(!cs) siz[x]=1;
if(siz[x]>1) Ckmax(ans,1ll*siz[x]*dep[x]);
}
signed main(){
scanf("%s",a+1);
n=strlen(a+1);
len[0]=IINF; a[n+1]='z'+1;
for(int i=1;i<=n+1;i++) Ukkonen(a[i]-'a');
dfs(1);
printf("%lld\n",ans);
return 0;
}
图论
匈牙利
int n,m,k;
int head[N],tot;
int mch[N];
bool vis[N];
struct Edge{
int to,nxt;
}edge[M];
void Add(int u,int v){
edge[++tot]={v,head[u]};
head[u]=tot;
}
bool dfs(int x){
for(int i=head[x];i;i=edge[i].nxt){
int t=edge[i].to;
if(vis[t]) continue;
vis[t]=1;
if(!mch[t]||dfs(mch[t])){
mch[t]=x;
return 1;
}
}
return 0;
}
signed main(){
read(n),read(m),read(k);
for(int i=1;i<=k;i++){
int u,v;
read(u),read(v);
Add(u,v);
}
int ans=0;
for(int i=1;i<=n;i++){
memset(vis,0,sizeof(vis));
ans+=dfs(i);
}
printf("%d\n",ans);
return 0;
}
KM
int n,m;
struct Edge{
int to,val;
};
vector<Edge> e[N];
ll ha[N],hb[N],upd[N];
bool va[N],vb[N];
int pre[N],mch[N];
void Clear(){
memset(va,0,sizeof(va));
memset(vb,0,sizeof(vb));
memset(upd,0x3f,sizeof(upd));
memset(pre,0,sizeof(pre));
}
bool dfs(int x,int pr){
va[x]=1;
for(Edge i:e[x]){
int t=i.to,w=i.val;
if(vb[t]) continue;
if(ha[x]+hb[t]==w){
vb[t]=1; pre[t]=pr;
if(!mch[t]||dfs(mch[t],t)){
mch[t]=x;
return 1;
}
}
else if(ha[x]+hb[t]-w<upd[t]){
upd[t]=ha[x]+hb[t]-w;
pre[t]=pr;
}
}
return 0;
}
void KMSolve(){
for(int i=1;i<=n;i++){
Clear();
int st=0; mch[0]=i;
while(mch[st]){
if(dfs(mch[st],st)) break;
ll delta=LINF;
for(int j=1;j<=n;j++){
if(!vb[j]&&upd[j]<delta)
delta=upd[j],st=j;
}
for(int j=1;j<=n;j++){
if(va[j]) ha[j]-=delta;
if(vb[j]) hb[j]+=delta;
else upd[j]-=delta;
}
vb[st]=1;
}
while(st){
mch[st]=mch[pre[st]];
st=pre[st];
}
}
ll ans=0;
for(int i=1;i<=n;i++) ans+=ha[i]+hb[i];
printf("%lld\n",ans);
for(int i=1;i<=n;i++) printf("%d ",mch[i]);
puts("");
}
signed main(){
read(n),read(m);
memset(ha,-0x3f,sizeof(ha));
for(int i=1;i<=m;i++){
int u,v,w;
read(u),read(v),read(w);
e[u].push_back(Edge{v,w});
Ckmax(ha[u],1ll*w);
}
KMSolve();
return 0;
}
最大流-Dinic
int n,m,S,T;
int head[N],tot=1,hd[N];
ll ans;
int dis[N];
struct Edge{
int to,nxt;
ll val;
}edge[M];
void Add(int u,int v,ll w){
edge[++tot]={v,head[u],w};
head[u]=tot;
}
bool Bfs(){
memset(dis,0,sizeof(dis));
queue<int> q;
q.push(S); hd[S]=head[S]; dis[S]=1;
while(q.size()){
int x=q.front(); q.pop();
for(int i=head[x];i;i=edge[i].nxt){
int y=edge[i].to;
if(!dis[y]&&edge[i].val){
dis[y]=dis[x]+1;
hd[y]=head[y];
if(y==T) return 1;
q.push(y);
}
}
}
return 0;
}
ll Dinic(int x,ll flow){
if(x==T) return flow;
ll res=0;
for(int &i=hd[x];i;i=edge[i].nxt){
int y=edge[i].to;
ll w=edge[i].val;
if(w&&dis[x]+1==dis[y]){
ll v=Dinic(y,min(flow-res,w));
if(!v) dis[y]=0;
edge[i].val-=v,edge[i^1].val+=v;
res+=v;
}
if(res==flow) break;
}
return res;
}
signed main(){
read(n),read(m),read(S),read(T);
for(int i=1;i<=m;i++){
int u,v; ll w;
read(u),read(v),read(w);
Add(u,v,w);
Add(v,u,0);
}
while(Bfs()) ans+=Dinic(S,LINF);
printf("%lld\n",ans);
return 0;
}
数论
Exgcd
ll T,A,B,C,x,y,d,x1,x2,y1,y2,cnt;
ll GetX(ll Y){return (C-B*Y)/A;}
ll GetY(ll X){return (C-A*X)/B;}
ll Exgcd(ll a,ll b,ll &x,ll &y){
if(b==0) return x=1,y=0,a;
ll res=Exgcd(b,a%b,x,y);
ll z=x;
x=y;
y=z-(a/b)*y;
return res;
}
void Solve(){
read(A),read(B),read(C);
d=Exgcd(A,B,x,y);
if(C%d) return puts("-1"),void();
A/=d,B/=d,C/=d;
x*=C,y*=C;
x1=((x-1)%B+B)%B+1;
y2=GetY(x1);
y1=((y-1)%A+A)%A+1;
x2=GetX(y1);
cnt=(x2-x1)/B+1;
if(y2<=0) printf("%lld %lld\n",x1,y1);
else printf("%lld %lld %lld %lld %lld\n",cnt,x1,y1,x2,y2);
}
CRT
ll n,m[N],a[N],ans,M=1,x,y;
ll Exgcd(ll a,ll b,ll &x,ll &y){
if(!b) return x=1,y=0,a;
ll res=Exgcd(b,a%b,x,y);
ll z=x;
x=y,y=z-a/b*y;
return res;
}
void Solve(){
for(int i=1;i<=n;i++) M*=m[i];
for(int i=1;i<=n;i++){
ll Mi=M/m[i];
ll d=Exgcd(Mi,m[i],x,y);
x=((x-1)%(m[i]/d)+m[i]/d)%(m[i]/d)+1;
ans=(ans+SlowMul(SlowMul(x,Mi),a[i]))%M;
}
printf("%lld\n",ans);
}
ExCRT
ll Solve(){
M=b[1],R=a[1];
for(int i=2;i<=n;i++){
ll A=M,B=b[i],C=a[i]-R;
C=(C%B+B)%B;
ll d=Exgcd(A,B,x,y);
if(C%d) return -1;
M=M/Exgcd(M,b[i],tmp1,tmp2)*b[i];
x=WangbaMul(x,C/d,B/d);
x=(x%(B/d)+(B/d))%(B/d);
R+=x*A; R%=M;
}
return R%M;
}
FWT
int n;
ll a[N],b[N],c[N];
ll ta[N],tb[N];
const ll mod=998244353,inv2=(mod+1)>>1;
inline ll Mod(ll x){return (x>=mod)?(x-mod):(x);}
inline void Add(ll &x,ll y){x=Mod(x+y);}
void FWTAnd(ll f[],int type){
for(int len=2;len<=n;len<<=1){
int k=len>>1;
for(int i=0;i<n;i+=len){
for(int j=0;j<k;j++){
Add(f[i+j],Mod(f[i+j+k]*type+mod));
}
}
}
}
void FWTOr(ll f[],int type){
for(int len=2;len<=n;len<<=1){
int k=len>>1;
for(int i=0;i<n;i+=len){
for(int j=0;j<k;j++)
Add(f[i+j+k],Mod(f[i+j]*type+mod));
}
}
}
void FWTXor(ll f[],int type){
for(int len=2;len<=n;len<<=1){
int k=len>>1;
for(int i=0;i<n;i+=len){
for(int j=0;j<k;j++){
Add(f[i+j],f[i+j+k]);
f[i+j+k]=Mod(f[i+j]-Mod(f[i+j+k]<<1)+mod);
if(type==-1) (f[i+j]*=inv2)%=mod,(f[i+j+k]*=inv2)%=mod;
}
}
}
}
void MulAnd(){
FWTAnd(a,1),FWTAnd(b,1);
for(int i=0;i<n;i++) c[i]=a[i]*b[i]%mod;
FWTAnd(c,-1);
}
void MulOr(){
FWTOr(a,1),FWTOr(b,1);
for(int i=0;i<n;i++) c[i]=a[i]*b[i]%mod;
FWTOr(c,-1);
}
void MulXor(){
FWTXor(a,1),FWTXor(b,1);
for(int i=0;i<n;i++) c[i]=a[i]*b[i]%mod;
FWTXor(c,-1);
}
signed main(){
read(n); n=1<<n;
for(int i=0;i<n;i++) read(a[i]);
for(int i=0;i<n;i++) read(b[i]);
memcpy(ta,a,sizeof(a)); memcpy(tb,b,sizeof(b));
MulOr(); for(int i=0;i<n;i++) printf("%lld ",c[i]); puts("");
memcpy(a,ta,sizeof(a)); memcpy(b,tb,sizeof(b));
MulAnd(); for(int i=0;i<n;i++) printf("%lld ",c[i]); puts("");
memcpy(a,ta,sizeof(a)); memcpy(b,tb,sizeof(b));
MulXor(); for(int i=0;i<n;i++) printf("%lld ",c[i]); puts("");
memcpy(a,ta,sizeof(a)); memcpy(b,tb,sizeof(b));
return 0;
}
FFT
int n,m,K;
int pos[N],ct;
const ld PI=acos(-1.0);
struct Cx{
ld r,i;
friend Cx operator + (Cx x,Cx y){return {x.r+y.r,x.i+y.i};}
friend Cx operator - (Cx x,Cx y){return {x.r-y.r,x.i-y.i};}
friend Cx operator * (Cx x,Cx y){return {x.r*y.r-x.i*y.i,x.r*y.i+x.i*y.r};}
}a[N],b[N],c[N];
void FFT(Cx f[],int type){
for(int i=0;i<K;i++) if(i<pos[i]) swap(f[i],f[pos[i]]);
for(int len=2;len<=K;len<<=1){
int k=len>>1;
Cx wn={cos(2*PI/len),type*sin(2*PI/len)};
for(int i=0;i<K;i+=len){
Cx w={1,0};
for(int j=0;j<k;j++,w=w*wn){
Cx x=f[i+j],y=w*f[i+j+k];
f[i+j]=x+y,f[i+j+k]=x-y;
}
}
}
}
signed main(){
read(n),read(m);
for(int i=0;i<=n;i++){
int v; read(v);
a[i]={v,0};
}
for(int i=0;i<=m;i++){
int v; read(v);
b[i]={v,0};
}
K=1,ct=0; while(K<=n+m) K<<=1,++ct;
for(int i=1;i<K;i++) pos[i]=(pos[i>>1]>>1)|((i&1)<<(ct-1));
FFT(a,1),FFT(b,1);
for(int i=0;i<K;i++) c[i]=a[i]*b[i];
FFT(c,-1);
for(int i=0;i<n+m+1;i++) printf("%d ",(int)(c[i].r/K+0.5));
return 0;
}
NTT
int n,m,K;
const ll mod=998244353,G=3,IG=332748118;
inline ll QuickPow(ll x,ll y){
ll res=1;
while(y){
if(y&1) res=res*x%mod;
x=x*x%mod; y>>=1;
}
return res;
}
ll a[N],b[N],c[N],pos[N];
void NTT(ll f[],int type){
for(int i=0;i<K;i++) if(i<pos[i]) swap(f[i],f[pos[i]]);
for(int len=2;len<=K;len<<=1){
int k=len>>1;
ll wn=QuickPow((type==1)?G:IG,(mod-1)/len);
for(int i=0;i<K;i+=len){
ll w=1;
for(int j=0;j<k;j++,(w*=wn)%=mod){
ll x=f[i+j],y=f[i+j+k]*w%mod;
f[i+j]=(x+y)%mod,f[i+j+k]=(x-y+mod)%mod;
}
}
}
}
signed main(){
read(n),read(m);
for(int i=0;i<=n;i++) read(a[i]);
for(int i=0;i<=m;i++) read(b[i]);
K=1; int ct=0; while(K<=n+m) K<<=1,++ct;
for(int i=1;i<K;i++) pos[i]=(pos[i>>1]>>1)|((i&1)<<(ct-1));
NTT(a,1),NTT(b,1);
for(int i=0;i<K;i++) c[i]=a[i]*b[i]%mod;
NTT(c,-1); ll inv=QuickPow(K,mod-2);
for(int i=0;i<K;i++) (c[i]*=inv)%=mod;
for(int i=0;i<n+m+1;i++) printf("%lld ",c[i]);
puts("");
return 0;
}