模板库
个人码风:大括号换行,4格缩进,轻微压行
注:代码中可能缺少以下缺省源:
#include<bits/stdc++.h>
using namespace std;
#define rep(i, a, b) for (register int i=(a); i<=(b); ++i)
#define per(i, a, b) for (register int i=(a); i>=(b); --i)
inline int read()
{
int x=0,f=1;char ch=getchar();
for (;ch<'0'||ch>'9';ch=getchar()) if (ch=='-') f=-1;
for (;ch>='0'&&ch<='9';ch=getchar()) x=(x<<1)+(x<<3)+ch-'0';
return x*f;
}
字符串
KMP
const int N=1000005;
char s[N], t[N];
int len_s, len_t, nxt[N];
void GetNext(char *s)
{
for (int i=2, k=0; i<=len_s; i++)
{
while (k && s[i]!=s[k+1]) k=nxt[k];
if (s[i]==s[k+1]) k++; nxt[i]=k;
}
}
void KMP(char *s, char *t)
{
for (int i=1, k=0; i<=len_t; i++)
{
while (k && t[i]!=s[k+1]) k=nxt[k];
if (t[i]==s[k+1]) k++;
if (k==len_s){printf("%d\n", i-len_s+1); k=nxt[k];}
}
}
SAM
inline void chkmax(int &x, int y){x<y?(x=y):0;}
inline void chkmin(int &x, int y){x>y?(x=y):0;}
const int N=1000005;
int son[N<<1][100], fa[N], len[N], last, cnt, n;//insert
int a[N], t[N], size[N];//sort
int mn[N], mx[N];//Get_N_LCS
int sum[N];//Get_Kth_Substr
int dp[N];//Get_N_Substr
long long ans;//Dif_Substr_Num
char s[N];
namespace SuffixAutoMaton
{
void clear()//for Dif_Substr_Num
{
memset(fa, 0, sizeof(fa));
memset(len, 0, sizeof(len));
memset(son, 0, sizeof(son));
ans=0;
}
void insert(int c)
{
int p=last, np=last=++cnt; len[np]=len[p]+1;
for (; p&&!son[p][c]; p=fa[p]) son[p][c]=np;
if (!p) fa[np]=1;
else
{
int q=son[p][c];
if (len[p]+1==len[q]) fa[np]=q;
else
{
int nq=++cnt; len[nq]=len[p]+1;
memcpy(son[nq], son[q], sizeof(son[q]));
fa[nq]=fa[q]; fa[q]=fa[np]=nq;
for (; son[p][c]==q; p=fa[p]) son[p][c]=nq;
}
}
size[np]=1;
//ans+=len[np]-len[fa[np]]; //for Dif_Substr_Num
}
void Sort()
{
for (int i=1; i<=cnt; i++) t[len[i]]++;
for (int i=1; i<=cnt; i++) t[i]+=t[i-1];
for (int i=1; i<=cnt; i++) a[t[len[i]]--]=i;
for (int i=cnt; i; i--) size[fa[a[i]]]+=size[a[i]];
}
void build()
{
scanf("%s", s+1); last=cnt=1; n=strlen(s+1);
for (int i=1; i<=n; i++) insert(s[i]-'A');
}
void Get_LCS()
{
build(); scanf("%s", s+1);
int n=strlen(s+1), p=1, Len=0, ans=0;
for (int i=1; i<=n; i++)
{
int c=s[i]-'a';
if (son[p][c]) p=son[p][c], Len++;
else
{
for (; p&&!son[p][c]; p=fa[p]);
if (p) Len=len[p]+1, p=son[p][c];
else p=1, Len=0;
}
ans=max(ans, Len);
}
printf("%d\n", ans);
}
void Get_N_LCS()
{
memset(mn, 0x3f, sizeof(mn));
build(); Sort(); int ans=0;
while (~scanf("%s", s+1))
{
int n=strlen(s+1), p=1, Len=0;
for (int i=1; i<=n; i++)
{
int c=s[i]-'a';
if (son[p][c]) Len++, p=son[p][c], chkmax(mx[p], Len);
else
{
for (; p&&!son[p][c]; p=fa[p]);
if (p) Len=len[p]+1, p=son[p][c], chkmax(mx[p], Len);
else Len=0, p=1;
}
}
for (int i=cnt; i; i--)
{
int u=a[i];
chkmax(mx[fa[u]], min(mx[u], len[fa[u]]));
chkmin(mn[u], mx[u]); mx[u]=0;
}
}
for (int i=1; i<=cnt; i++) chkmax(ans, mn[i]);
printf("%d\n", ans);
}
void Get_Kth_Dif_Substr()
{
Sort();
for (int i=1; i<=cnt; i++) sum[i]=size[i]=1; sum[1]=size[1]=0;
for (int i=cnt; i; i--)
for (int j=0; j<26; j++) sum[a[i]]+=sum[son[a[i]][j]];
int k=read(), u=1;
if (sum[1]<k) {puts("-1"); exit(0);}
while (k>0)
{
for (int i=0; i<26; i++) if (son[u][i])
{
if (sum[son[u][i]]<k) k-=sum[son[u][i]];
else{putchar(i+'a'); u=son[u][i]; k--; break;}
}
}
puts("");
}
void Get_Kth_Substr()
{
Sort();
for (int i=1; i<=cnt; i++) sum[i]=size[i]; sum[1]=size[1]=0;
for (int i=cnt; i; i--)
for (int j=0; j<26; j++) sum[a[i]]+=sum[son[a[i]][j]];
int k=read(), u=1; if (sum[1]<k) {puts("-1"); exit(0);}
while (k>0)
{
for (int i=0; i<26; i++) if (son[u][i])
{
if (sum[son[u][i]]<k) k-=sum[son[u][i]];
else{putchar(i+'a'); u=son[u][i]; k-=size[u]; break;}
}
}
puts("");
}
void Get_N_Substr()
{
build(); Sort();
for (int i=cnt; i; i--) chkmax(dp[len[a[i]]], size[a[i]]);
for (int i=n-1; i; i--) chkmax(dp[i], dp[i+1]);
for (int i=1; i<=n; i++) printf("%d\n", dp[i]);
}
void Dif_Substr_Num()
{
int T=read();
while (T--) clear(), build(), printf("%lld\n", ans);
}
}
SA
const int N=2000005;
int sa[N], rnk[N], top[N], tax[N], n, m;
int h[N], st[N][24], log_2[N];
char s[N];
namespace SuffixArray
{
inline void SuffixSort()
{
scanf("%s", s+1); n=strlen(s+1); m=122;
memset(tax, 0, sizeof(tax));
for (int i=1; i<=n; i++) tax[rnk[i]=(int)s[i]]++;
for (int i=1; i<=m; i++) tax[i]+=tax[i-1];
for (int i=n; i; i--) sa[tax[rnk[i]]--]=i;
for (int p=1; p<=n; p<<=1)
{
int t=0;
for (int i=n-p+1; i<=n; i++) top[++t]=i;
for (int i=1; i<=n; i++) if (sa[i]>p) top[++t]=sa[i]-p;
memset(tax, 0, sizeof(tax));
for (int i=1; i<=n; i++) tax[rnk[i]]++;
for (int i=1; i<=m; i++) tax[i]+=tax[i-1];
for (int i=n; i; i--) sa[tax[rnk[top[i]]]--]=top[i];
memcpy(top, rnk, sizeof(rnk)); rnk[sa[1]]=t=1;
for (int i=2; i<=n; i++)
rnk[sa[i]]=(top[sa[i-1]]==top[sa[i]]
&& top[sa[i-1]+p]==top[sa[i]+p])? t : ++t;
if (t==n) break; m=t;
}
}
void Height()
{
int k=0;
for (int i=1; i<=n; i++) rnk[sa[i]]=i;
for (int i=1; i<=n; i++)
{
int j=sa[rnk[i]-1]; k?k--:0;
while (s[i+k]==s[j+k]) k++; h[rnk[i]]=k;
}
}
void ST()
{
for (int i=1; i<=n; i++) st[i][0]=h[i+1];
for (int p=1; (1<<p)<n; p++)
for (int i=1; i+(1<<p)-1<=n; i++)
st[i][p]=min(st[i][p-1], st[i+(1<<(p-1))][p-1]);
log_2[1]=0;
for (int i=2; i<=n; i++) log_2[i]=log_2[i>>1]+1;
}
int LCP(int l, int r)
{
int p=log_2[r-l+1];
return min(st[l][p], st[r-(1<<p)+1][p]);
}
}
AC自动机(Trie图)
const int N=1000005;
struct node{int fail, num, son[26];}t[N];
int cnt; char s[N];
namespace Aho_Corasick_Automaton
{
void insert(char *s)
{
int len=strlen(s+1), p=0;
for (int i=1; i<=len; i++)
{
int c=s[i]-'a';
if (!t[p].son[c]) t[p].son[c]=++cnt;
p=t[p].son[c];
}
t[p].num++;
}
void build_AC()
{
queue<int> q;
for (int i=0; i<26; i++) if (t[0].son[i]) q.push(t[0].son[i]);
while (!q.empty())
{
int now=q.front(), fail=t[now].fail; q.pop();
for (int i=0; i<26; i++)
{
int son=t[now].son[i];
if(son) t[son].fail=t[fail].son[i], q.push(son);
else t[now].son[i]=t[fail].son[i];
}
}
}
int find(char *s)
{
int len=strlen(s+1), pos=0, res=0;
for (int i=1; i<=len; i++)
{
int c=s[i]-'a', now=pos=t[pos].son[c];
while (now && t[now].num!=-1)
{
res+=t[now].num; t[now].num=-1;
now=t[now].fail;
}
}
return res;
}
void Build()
{
for (int i=1, n=read(); i<=n; i++)
scanf("%s", s+1), insert(s);
build_AC();
}
}
Manacher
const int N=11000005;
char t[N], s[N<<1]; int p[N<<1];
int main()
{
scanf("%s", t+1); int n=strlen(t+1), ans=0;
for (int i=1; i<=n; i++) s[i<<1]=t[i], s[i<<1|1]='#';
(n<<=1)+=2; s[1]=s[n]='#';
for (int i=1, maxr=0, mid=0; i<=n; i++)
{
p[i]=(i<maxr)?min(p[2*mid-i], p[mid]+mid-i):1;
while (i+p[i]<=n && s[i+p[i]]==s[i-p[i]]) p[i]++;
if (p[i]+i>maxr) maxr=p[i]+i, mid=i;
}
for (int i=1; i<=n; i++) ans=max(ans, p[i]-1);
printf("%d\n", ans);
return 0;
}
最小表示法
int main()
{
int n=read(), k=0, i=0, j=1;
for (int i=0; i<n; i++) a[i]=read();
while (k<n && i<n && j<n)
{
if (a[(i+k)%n]==a[(j+k)%n]) k++;
else
{
a[(i+k)%n]>a[(j+k)%n]?i=i+k+1:j=j+k+1;
i==j?i++:0; k=0;
}
} j=min(i, j);
for (int i=j; i<n; i++) printf("%d ", a[i]);
for (int i=0; i<j; i++) printf("%d ", a[i]);
}
数学
快速幂
int Pow(int x, int t)
{
int res=1;
while (t)
{
if (t&1) res=1ll*res*x%p;
x=1ll*x*x%p; t>>=1;
}
return res;
}
逆元
inv[1]=1; for (int i=2; i<=n; i++) inv[i]=1ll*(p-p/i)*inv[p%i]%p;//线性求逆元
int fac=1; for (int i=1; i<=n; i++) fac=1ll*fac*i%p;
ifac[n]=Pow(fac, p-2); for (int i=n-1; i; i--) ifac[i]=1ll*ifac[i+1]*(i+1)%p;//线性求阶乘逆元
void Exgcd(int a, int b, int &x, int &y)
{
if (!b) x=1, y=0;
else Exgcd(b, a%b, y, x), y-=a/b*x;
}
int inv(int a, int p)
{
int x, y;
Exgcd(a, p, x, y);
return (x%p+p)%p;
}//扩展欧几里得求逆元
Lucas定理
int C(int n, int m)
{
if (n<m) return 0;
return (fac[n] * Pow(fac[m], p-2) % p) * Pow(fac[n-m], p-2) % p;
}
int Lucas(int n, int m, int p)
{
if (!m) return 1;
return Lucas(n/p, m/p) * C(n%p, m%p) % p;
}
线性基
for (int i=1; i<=n; i++)
{
int x=read();
for (int j=max_log; ~j; j--) if (x>>j)
{if (!p[j]) {p[j]=x; break;} else x^=p[j];}
}
for (int i=max_log; i>=0; i--) ans=max(ans, ans^p[i]);
//Max_Xor_Sum
线性筛素数
void Euler_Prime(int n)
{
memset(isprime, true, sizeof(isprime)); isprime[1]=0;
int cnt=0;
for (int i=2; i<=n; i++)
{
if (isprime[i]) prime[++cnt]=i;
for (int j=1; j<=cnt && i*prime[j]<=n; j++)
{
isprime[i*prime[j]]=false;
if (!(i%prime[j])) break;
}
}
}
void Get_Phi(int n)
{
memset(isprime, true, sizeof(isprime)); isprime[1]=0;
int cnt=0;
for (int i=2; i<=n; i++)
{
if (isprime[i]) prime[++cnt]=i, phi[i]=i-1;
for (int j=1; j<=cnt && i*prime[j]<=n; j++)
{
isprime[i*prime[j]]=0;
if (!(i%prime[j])) {phi[i*prime[j]]=phi[i]*prime[j]; break;}
else phi[i*prime[j]]=phi[i]*(prime[j]-1);
}
}
}
void Get_Mu(int n)
{
memset(isprime, true, sizeof(isprime)); isprime[1]=0; mu[1]=1;
int cnt=0;
for (int i=2; i<=n; i++)
{
if (isprime[i]) prime[++cnt]=i, mu[i]=-1;
for (int j=1; j<=cnt && i*prime[j]<=n; j++)
{
isprime[i*prime[j]]=0;
if (!(i%prime[j])) break;
else mu[i*prime[j]]=-mu[i];
}
}
}
矩阵快速幂
struct Matrix
{
int n, m; long long sq[N][N];
Matrix(int _n, int _m){n=_n; m=_m; memset(sq, 0, sizeof(sq));}
Matrix operator + (Matrix a)
{
Matrix ans(n, m);
for(int i=1; i<=n; i++) for(int j=1; j<=m; j++)
ans.sq[i][j]=(sq[i][j] + a.sq[i][j])%P;
return ans;
}
Matrix operator * (Matrix a)
{
Matrix ans(n, a.m);
for(int i=1; i<=n; i++) for(int j=1; j<=a.m; j++)
{
long long tmp=0;
for(int k=1; k<=m; k++)
tmp=(tmp+((long long)sq[i][k]*a.sq[k][j])%P)%P;
ans.sq[i][j]=tmp;
}
return ans;
}
};
Matrix Pow (Matrix a, long long n)
{
Matrix ans(a.n, a.n), tmp(a.n, a.n);
for(int i=1; i<=a.n; i++) ans.sq[i][i]=1;
memcpy(tmp.sq, a.sq, sizeof(tmp.sq));
while(n)
{
if(n&1) ans=ans*tmp;
n>>=1; tmp=tmp*tmp;
}
return ans;
}
拉格朗日插值
int Lagrange(int *x, int *y, int n, int k)
{
int res=0;
for (int i=1; i<=n; i++)
{
int s1=1, s2=1;
for (int j=1; j<=n; j++) if (i^j)
{
s1=1ll*s1*(k-x[j])%P;
s2=1ll*s2*(x[i]-x[j])%P;
}
res=(res+1ll*(1ll*s1*Pow(s2, P-2)%P)*y[i])%P;
}
return (res%P+P)%P;
}//O(n^2)
int Lagrange(int *y,int n,int k)
{
int ans=0, fac=1; pre[0]=suf[n+1]=1; ifac[n]=Pow(fac, P-2);
for (int i=1; i<=n; i++) pre[i]=1ll*pre[i-1]*(k-i)%P;
for (int i=n; i; i--) suf[i]=1ll*suf[i+1]*(k-i)%P;
for (int i=1; i<=n; i++) fac=1ll*fac*i%P;
for (int i=n-1; i; i--) ifac[i]=1ll*ifac[i+1]*(i+1)%P;
for (int i=1; i<=n; i++)
{
int s1=1ll*pre[i-1]*suf[i+1]%P;
int s2=1ll*ifac[i-1]*ifac[n-i]%P;
ans=(ans+1ll*((n-i)&1?-1:1)*s1*s2%P*y[i])%P;
}
return (ans%P+P)%P;
}//O(n)
Miller Rabin
#define int long long
const int times=10;
int mul(int x, int t, int P)
{
int res=0;
for (; t; t>>=1, x=(x+x)%P) if (t&1) res=(res+x)%P;
return res;
}
int Pow(int x, int t, int P)
{
int res=1;
for (; t; t>>=1, x=mul(x, x, P)) if (t&1) res=mul(res, x, P);
return res;
}
bool check(int a, int p)
{
int x=p-1, k=0;
while (!(x&1)) x>>=1, k++;
x=Pow(a, x, p);
if (x==1) return true;
rep(i, 1, k)
{
if (x==p-1) return true;
x=mul(x, x, p);
}
return false;
}
bool Miller_Rabin(int x)
{
if (x==2) return true;
if (x<2) return false;
rep(i, 1, times)
{
int a=rand()%(x-2)+2;
if (!check(a, x)) return false;
}
return true;
}
Pollard Rho
#define int long long
const int times=10;
int max(int a, int b){return a>=b?a:b;}
int sub(int a, int b){return a>=b?a-b:b-a;}
int gcd(int a, int b){return b?gcd(b, a%b):a;}
int mul(int x, int y, int P)
{
int t=(long double)x*y/P;
return ((x*y-t*P)%P+P)%P;
}
int Pow(int x, int t, int P)
{
int res=1;
for (; t; t>>=1, x=mul(x, x, P)) if (t&1) res=mul(res, x, P);
return res;
}
bool check(int a, int p)
{
int x=p-1, k=0;
while (!(x&1)) x>>=1, k++;
x=Pow(a, x, p);
if (x==1) return true;
rep(i, 1, k)
{
if (x==p-1) return true;
x=mul(x, x, p);
}
return false;
}
bool Miller_Rabin(int x)
{
if (x==2) return true;
if (x<2) return false;
rep(i, 1, times)
{
int a=rand()%(x-2)+2;
if (!check(a, x)) return false;
}
return true;
}
int solve(int n, int step, int add)
{
if (!(n&1)) return 2;
int x=2, y=2, d=1;
while (1)
{
int tx=x, ty=y;
rep(i, 1, step)
{
x=mul(x, x, n)+add; if (x>=n) x-=n;
y=mul(y, y, n)+add; if (y>=n) y-=n;
y=mul(y, y, n)+add; if (y>=n) y-=n;
d=mul(d, sub(x, y), n);
}
d=gcd(n, d);
if (d==1) continue;
if (d^n) return d;
x=tx; y=ty;
rep(i, 1, step)
{
x=mul(x, x, n)+add; if (x>=n) x-=n;
y=mul(y, y, n)+add; if (y>=n) y-=n;
y=mul(y, y, n)+add; if (y>=n) y-=n;
d=gcd(n, sub(x, y));
if (d^1) return d%n;
}
return 0;
}
}
int Rho(int n)
{
if (Miller_Rabin(n)) return n;
int tmp=0, step=pow(n, 0.1), add=0;
while (!tmp) tmp=solve(n, step, ++add);
return max(Rho(tmp), Rho(n/tmp));
}
原根
void Sieve(int MAX)
{
for (int i=2; i<=MAX; i++)
{
if (!vis[i]) p[++cnt]=i;
for (int j=1; j<=cnt && p[j]*i<=MAX; j++)
{
vis[p[j]*i]=1;
if (!(i%p[j])) break;
}
}
}
int Pow(int x, int t)
{
int res=1;
for (; t; t>>=1, x=1ll*x*x%P) if (t&1) res=1ll*res*x%P;
return res;
}
void GetFactor(int n)
{
for (int i=1; i<=cnt; i++)
{
if (n<p[i]*p[i]) return;
if (!(n%p[i])) fac[++tot]=p[i];
}
}
bool IsRoot(int n)
{
for (int i=1; i<=tot; i++)
if (Pow(n, (P-1)/fac[i])==1) return false;
return true;
}
int GetRoot(int P);
{
Sieve(31623); GetFactor(P-1);
for (int i=2; ; i++) if (IsRoot(i)) return i;
}
康托展开
void Add(int x, int d){for (; x <= n; x += x & -x) t[x] += d;}
int Query(int x)
{
int res = 0;
for (; x; x -= x & -x) res += t[x];
return res;
}
int Cantor()
{
n = read(); fac[0] = 1;
for (int i = 1; i <= n; ++i) p[i] = read();
for (int i = 1; i <= n; ++i) fac[i] = mul(fac[i - 1], i);
for (int i = 1; i <= n; ++i) Add(i, 1);
for (int i = 1; i <= n; ++i)
{
ans=add(ans, mul(sub(Query(p[i]), 1), fac[n - i]));
Add(p[i], -1);
}
return add(ans, 1);
}
图论
最大流(Dinic)
const int N = 500, M = 1000;
struct node{int to, nxt, flow;}edge[M];
int head[N], cur[N], dep[N], cnt, n, S, T;
void pre(){memset(head, -1, sizeof(head)); cnt=-1;}
void add(int u, int v, int w)
{
edge[++cnt] = (node){v, head[u], w};
head[u] = cnt;
edge[++cnt] = (node){u, head[v], 0};
head[v] = cnt;
}
bool bfs()
{
memset(dep, 0, sizeof(dep));
dep[S] = 1;
queue<int> q;
q.push(S);
memcpy(cur, head, sizeof(head));
while (!q.empty())
{
int u = q.front(); q.pop();
for (int i = head[u]; ~i; i = edge[i].nxt)
{
int v = edge[i].to, f = edge[i].flow;
if (f && !dep[v]) dep[v] = dep[u] + 1, q.push(v);
}
}
return dep[T];
}
int dfs(int u, int lim)
{
if (!lim || u == T) return lim;
int addflow = 0, flow;
for (int i = cur[u]; ~i; i = edge[i].nxt)
{
cur[u] = i;
int v = edge[i].to, f = edge[i].flow;
if (dep[v] == dep[u] + 1 && (flow = dfs(v, min(lim, f))))
{
addflow += flow;
lim -= flow;
edge[i].flow -= flow;
edge[i ^ 1].flow += flow;
if (!lim) break;
}
}
return addflow;
}
int Dinic()
{
int maxflow = 0;
while (bfs())
maxflow += dfs(S, 1<<30);
return maxflow;
}
费用流(EK&spfa)
const int N=10005, M=1000005;
struct node{int to, nxt, flow, cost;}edge[M];
int head[N], flow[N], cost[N], pre[N], last[N], cnt;
int vis[N], S, T;
void prep(){memset(head, -1, sizeof(head)); cnt=-1;}
void add(int u, int v, int f, int w)
{
edge[++cnt]=(node){v, head[u], f, w};
head[u]=cnt;
edge[++cnt]=(node){u, head[v], 0, -w};
head[v]=cnt;
}
bool spfa()
{
memset(cost, 0x3f, sizeof(cost)); cost[S]=0;
memset(flow, 0x3f, sizeof(flow));
memset(vis, 0, sizeof(vis)); vis[S]=1;
queue<int> q; q.push(S); pre[T]=-1;
while (!q.empty())
{
int u=q.front(); q.pop();
for (int i=head[u]; ~i; i=edge[i].nxt)
{
vis[u]=0;
int v=edge[i].to, w=edge[i].cost, f=edge[i].flow;
if (f>0 && cost[u]+w<cost[v])
{
cost[v]=cost[u]+w;
pre[v]=u; last[v]=i;
flow[v]=min(flow[u], f);
if (!vis[v]) vis[v]=1, q.push(v);
}
}
}
return ~pre[T];
}
int EK()
{
int maxflow=0, mincost=0;
while (spfa())
{
maxflow+=flow[T]; mincost+=flow[T]*cost[T];
int u=T;
while (u^S)
{
edge[last[u]].flow-=flow[T];
edge[last[u]^1].flow+=flow[T];
u=pre[u];
}
}
return mincost;
}
点分治(路径长为\(K\)的条数)
inline void chkmax(int &x, int y){x<y?(x=y):0;}
const int N=10005;
vector<pair<int, int> > G[N];
int size[N], Max[N], dis[N], vis[N];
int sum, cnt, rt, n, m, K; long long ans;
#define v i.first
#define w i.second
void GetRoot(int u, int fa)
{
size[u]=1; Max[u]=0;
for (auto i: G[u]) if (v^fa && !vis[v])
GetRoot(v, u), chkmax(Max[u], size[v]), size[u]+=size[v];
chkmax(Max[u], sum-size[u]);
if (Max[u]<Max[rt]) rt=u;
}
int LeftBound(int l, int x)
{
int ans=0, r=cnt;
while (l<=r)
{
int mid=l+r>>1;
if (dis[mid]<x) l=mid+1;
else ans=mid, r=mid-1;
}
return ans;
}
int RightBound(int l, int x)
{
int ans=0, r=cnt;
while (l<=r)
{
int mid=l+r>>1;
if (dis[mid]>x) r=mid-1;
else ans=mid, l=mid+1;
}
return ans;
}
void GetDis(int u, int fa, int Dis)
{
for (auto i: G[u]) if (v^fa && !vis[v])
dis[++cnt]=Dis+w, GetDis(v, u, dis[cnt]);
}
int GetAns(int u, int Dis)
{
dis[cnt=1]=Dis; GetDis(u, 0, Dis);
sort(dis+1, dis+cnt+1);
int l=1, ans=0;
while (l<cnt && dis[l]+dis[cnt]<K) l++;
while (l<cnt && (dis[l]<<1)<=K)
{
int DisL=LeftBound(l+1, K-dis[l]);
int DisR=RightBound(l+1, K-dis[l]);
if (DisR>=DisL) ans+=DisR-DisL+1;
l++;
}
return ans;
}
void dfs(int u)
{
vis[u]=1; ans+=GetAns(u, 0);
for (auto i: G[u]) if (!vis[v])
{
ans-=GetAns(v, w);
sum=size[v]; rt=0; GetRoot(v, u); dfs(rt);
}
}
#undef v
#undef w
void add(int u, int v, int w)
{
G[u].push_back(make_pair(v, w));
G[v].push_back(make_pair(u, w));
}
朱刘算法(最小树形图)
const int N=105, M=10005, inf=0x3f3f3f3f;
struct edge{int u, v, w;}E[M];
int In_val[N], In_ver[N], vis[N], id[N], n, m, rt;
int ZhuLiu()
{
int ans = 0;
while (1)
{
memset(In_val, 0x3f, sizeof(In_val));
for (int i = 1; i <= m; ++i)
{
int u = E[i].u, v = E[i].v, w = E[i].w;
if (u ^ v && w < In_val[v]) In_val[v]=w, In_ver[v]=u;
}
for (int i = 1; i <= n; ++i)
if (i ^ rt && In_val[i] == inf) return -1;
int cnt = 0;
memset(vis, 0, sizeof(vis));
memset(id, 0, sizeof(id));
for (int i = 1; i <= n; ++i) if (i ^ rt)
{
int u = i; ans += In_val[u];
while (vis[u] ^ i && !id[u] && u ^ rt)
vis[u] = i, u = In_ver[u];
while (!id[u] && u ^ rt)
{
id[u] = ++cnt;
for (int v = In_ver[u]; v ^ u; v = In_ver[v]) id[v] = cnt;
}
}
if (!cnt) return ans;
for (int i = 1; i <= n; ++i) if (!id[i]) id[i] = ++cnt;
for (int i = 1; i <= m; ++i)
{
int u = E[i].u, v = E[i].v;
E[i].u = id[u]; E[i].v = id[v];
if (id[u] ^ id[v]) E[i].w -= In_val[v];
}
rt = id[rt]; n = cnt;
}
}
数据结构
左偏树
int Merge(int x, int y)
{
if (!x || !y) return x|y;
if (a[x]<a[y] || (a[x]==a[y] && x>y)) swap(x, y);
rs[x]=Merge(rs[x], y);
if (dis[ls[x]]<dis[rs[x]]) swap(ls[x], rs[x]);
dis[x]=dis[rs[x]]+1;
return x;
}
int Delete(int x){return Merge(ls[x], rs[x]);}
多项式
FFT
const double pi = acos(-1.0);
namespace ComplexOperator
{
struct complex
{
double x, y;
complex(double _x = 0.0, double _y = 0.0)
{ x = _x; y = _y; }
};
complex operator + (complex a, complex b)
{
return complex(
a.x + b.x,
a.y + b.y
);
}
complex operator - (complex a, complex b)
{
return complex(
a.x - b.x,
a.y - b.y
);
}
complex operator * (complex a, complex b)
{
return complex(
a.x * b.x - a.y * b.y,
a.x * b.y + a.y * b.x
);
}
}
using namespace ComplexOperator;
const int N = 4e6 + 5;
complex a[N], b[N];
int rev[N];
void FFT(complex *a, int n, int x)
{
for (int i = 0; i < n; ++i)
if (i < rev[i]) swap(a[i], a[rev[i]]);
for (int i = 1; i < n; i <<= 1)
{
complex Wn = complex(cos(pi / i), sin(pi / i) * x);
for (int j = 0; j < n; j += (i << 1))
{
complex W = complex(1, 0);
for (int k = 0; k < i; ++k, W = W * Wn)
{
complex A1 = a[j + k];
complex A2 = W * a[i + j + k];
a[j + k] = A1 + A2;
a[i + j + k] = A1 - A2;
}
}
}
}
void multiply(complex a[], complex b[], int n, int m)
{
int limit = 1, cnt = 0;
while (limit <= n + m) limit <<= 1, ++cnt;
for (int i = 0; i < limit; ++i)
rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << (cnt - 1));
FFT(a, limit, 1);
FFT(b, limit, 1);
for (int i = 0; i <= limit; ++i) a[i] = a[i] * b[i];
FFT(a, limit, -1);
for (int i = 0; i <= n + m; ++i) a[i].x = (int)(a[i].x / limit + 0.5);
}
NTT
const int N=4000005, P=998244353, G=3;
inline int add(int x, int y){return x+y>=P?x+y-P:x+y;}
inline int sub(int x, int y){return x-y<0?x-y+P:x-y;}
inline int mul(int x, int y){return 1ll*x*y-1ll*x*y/P*P;}
int a[N], b[N], rev[N];
int Pow(int x, int t)
{
int res=1;
for (; t; t>>=1, x=mul(x, x)) if (t&1) res=mul(res, x);
return res;
}
void NTT(int *a, int n, int x)
{
for (int i=0; i<n; i++) if (i<rev[i]) swap(a[i], a[rev[i]]);
for (int mid=1, len=2; mid<n; mid<<=1, len<<=1)
{
int Gn=Pow(G, (P-1)/len);
for (int i=0; i<n; i+=len)
{
int Gen=1;
for (int j=0; j<mid; j++, Gen=mul(Gen, Gn))
{
int A1=a[i+j], A2=mul(Gen, a[i+j+mid]);
a[i+j]=add(A1, A2); a[i+j+mid]=sub(A1, A2);
}
}
}
if (!~x) reverse(a+1, a+n);
}
void solve()
{
int n=read(), m=read(), lim=1, cnt=0;
while (lim<=n+m) lim<<=1, cnt++;
rep(i, 0, n) a[i]=read();
rep(i, 0, m) b[i]=read();
rep(i, 0, lim) rev[i] = (rev[i>>1] >> 1) | ((i & 1) << (cnt - 1));
NTT(a, lim, 1); NTT(b, lim, 1);
rep(i, 0, lim) a[i]=mul(a[i], b[i]);
NTT(a, lim, -1);
lim=Pow(lim, P-2);
rep(i, 0, n+m) printf("%d ", mul(a[i], lim));
}