代码仓库
二次剩余
ll n,p,w;
int t;
inline ll ksm(ll a,ll b){
ll res=1;
while(b){
if(b&1) res=(res*a)%p;
a=(a*a)%p;
b>>=1;
}
return (res%p+p)%p;
}
inline ll lrd(ll x){
return ksm(x,(p-1)>>1);
}
struct rode{
ll x,y;
inline void intt(ll x_,ll y_){
x=x_;y=y_;
}
};
inline rode operator * (const rode &a,const rode &b){
rode c;c.intt(((a.x*b.x)%p+a.y*b.y%p*w%p)%p,(a.x*b.y%p+a.y*b.x%p)%p);
return c;
}
inline rode operator ^ (rode a,ll b){
rode c;c.intt(1,0);
while(b){
if(b&1) c=c*a;
a=a*a;
b>>=1;
}
return c;
}
inline void solve(ll x){
int if_=lrd(x);
if(if_==p-1) printf("Hola!\n");
else if(if_==0) printf("0\n");
else{
ll q=rand()%p;w=(((q*q)%p-n)%p+p)%p;
while(lrd(w)<=1) q=rand()%p,w=(((q*q)%p-n)%p+p)%p;
rode a;a.intt(q,1);
a=a^((p+1)>>1);
ll ans1=a.x,ans2=p-ans1;
if(ans1>ans2) ans1^=ans2,ans2^=ans1,ans1^=ans2;
printf("%lld %lld\n",ans1,ans2);
}
}
int main(){
srand(time(0));
scanf("%d",&t);
while(t--){
scanf("%lld%lld",&n,&p);
solve(n);
}
return 0;
}
李超树
#define f(i,x) (K[(i)]*(x)+B[(i)])
#define ls(k) k<<1
#define rs(k) k<<1|1
inline void Change(int k,int l,int r,int z,int y,int id){
// if(id==243) printf("z=%d y=%d\n",z,y);
// printf("k=%d l=%d r=%d z=%d y=%d id=%d v[k]=%d\n",k,l,r,z,y,id,v[k]);
if(l==r){if(!v[k]||f(v[k],l)<f(id,l)) v[k]=id;return;}
int mid=(l+r)>>1;
if(z<=l&&r<=y){
if(!v[k]) v[k]=id;
if(f(v[k],mid)<f(id,mid)) swap(v[k],id);
(f(v[k],l)<f(id,l))?Change(ls(k),l,mid,z,y,id):Change(rs(k),mid+1,r,z,y,id);
}
else{
if(z<=mid) Change(ls(k),l,mid,z,y,id);if(y>mid) Change(rs(k),mid+1,r,z,y,id);
}
}
inline int Ask(int k,int l,int r,int w){
if(l==r) return v[k];int mid=(l+r)>>1;
int nowid;if(w<=mid) nowid=Ask(ls(k),l,mid,w);else nowid=Ask(rs(k),mid+1,r,w);
// printf("k=%d l=%d r=%d w=%d nowid=%d v[k]=%d\n",k,l,r,w,nowid,v[k]);
return (f(v[k],w)<f(nowid,w))?nowid:v[k];
}
dinic 费用流
inline bool spfa(){
mset(vis,0);q.push(s);vis[s]=1;mset(d,INF);d[s]=0;
while(q.size()){
int top=q.front();q.pop();now[top]=head[top];vis[top]=0;
Next(top){
int to=li[x].to,w=li[x].w,f=li[x].f;
if(d[to]<=d[top]+w||!f) continue;
d[to]=d[top]+w;if(!vis[to]) q.push(to),vis[to]=1;
}
}
if(d[t]==INF) return 0;return 1;
}
inline int dinic(int k,int flow){
if(k==t) return flow;vis[k]=1;int rest=flow,x;
for(x=now[k];x;x=li[x].next){
int to=li[x].to,w=li[x].w,f=li[x].f;
if((vis[to]&&to!=t)||d[to]!=d[k]+w||!f) continue;int now=dinic(to,min(rest,f));if(!now) d[to]=INF;
rest-=now;li[x].f-=now;li[x^1].f+=now;Ans+=w*now;
if(!rest) break;
}
now[k]=x;return flow-rest;
}
- 注意 dinic 函数中第三个判断条件不能省。
- \(\text{d[t]}\) 的判断一定要放在最后。
原因:对于第一个,可能会有负环,就会陷入死循环。对于第二个,如果不放在最后,可能会导致最短路不优,而导致答案变大。
LCT
#define ls(k) ch[k][0]
#define rs(k) ch[k][1]
struct LCT{
inline int Get(int k){return rs(fa[k])==k;}
inline void PushUp(int k){
val[k]=a[k]^val[ls(k)]^val[rs(k)];
}
inline void C(int k){
swap(ls(k),rs(k));tag[k]^=1;
}
inline void PushDown(int k){
if(tag[k]){
C(ls(k));C(rs(k));tag[k]^=1;;
}
}
inline bool Root(int k){
int fat=fa[k];
return ls(fat)!=k&&rs(fat)!=k;
}
inline void rotate(int k){
int y=fa[k];int z=fa[y],x=Get(k);
if(!Root(y)) ch[z][Get(y)]=k;
ch[y][x]=ch[k][x^1];fa[ch[k][x^1]]=y;
ch[k][x^1]=y;fa[y]=k;fa[k]=z;
PushUp(y);PushUp(k);
}
inline void Update(int k){
if(!Root(k)) Update(fa[k]);
PushDown(k);
}
inline void Splay(int k){
Update(k);
for(int f=fa[k];!Root(k);rotate(k),f=fa[k]){
if(!Root(f)) rotate(Get(k)==Get(f)?f:k);
}
}
inline int Access(int k){
int p;
for(p=0;k;p=k,k=fa[k]){
Splay(k);rs(k)=p;PushUp(k);
}
return p;
}
inline void MakeRoot(int k){
k=Access(k);C(k);
}
inline void Split(int x,int y){
MakeRoot(x);Access(y);Splay(y);
}
inline int Find(int k){
Access(k);Splay(k);PushDown(k);
while(ls(k)) k=ls(k),PushDown(k);
Splay(k);return k;
}
inline void Cut(int a,int b){
MakeRoot(a);
if(Find(b)==a&&rs(a)==b&&ls(b)==0){
rs(a)=fa[b]=0;PushUp(a);
}
}
inline void Link(int a,int b){
MakeRoot(a);if(Find(b)==a) return;Splay(a);fa[a]=b;
}
inline void Change(int k,int x){
MakeRoot(k);a[k]=x;PushUp(k);
}
inline int Ask(int a,int b){
Split(a,b);return val[b];
}
}lct;
后缀自动机
struct node{
int len,link,ch[26];
};
struct SAM{
node p[N];
int size,last;
inline SAM(){
p[0].len=0;p[0].link=-1;last=0;
}
inline void insert(int c){
int cur=++size;f[size]++;
p[cur].len=p[last].len+1;
int now=last;
while(now!=-1&&!p[now].ch[c]){
p[now].ch[c]=cur;
now=p[now].link;
}
if(now==-1) p[cur].link=0;
else{
int q=p[now].ch[c];
if(p[now].len+1==p[q].len) p[cur].link=q;
else{
int clone=++size;
p[clone]=p[q];p[clone].len=p[now].len+1;
while(now!=-1&&p[now].ch[c]==q){
p[now].ch[c]=clone;now=p[now].link;
}
p[q].link=p[cur].link=clone;
}
}
last=cur;
}
};
SAM sam;
实现 Prufer 序列和无根树的双射 O(n) 算法
int n,m,d[N];
namespace Subtask1{
int k=INF,fa[N],p[N];
inline void Solve(){
for(int i=1;i<=n-1;i++){
int x;read(x);
d[x]++;d[i]++;fa[i]=x;
}
for(int i=1,j=1;i<=n-2;i++,j++){
while(d[j]!=1) j++;p[i]=fa[j];d[j]--;d[fa[j]]--;
while(i<=n-2&&d[p[i]]==1&&p[i]<j){p[i+1]=fa[p[i]];d[p[i]]--;d[fa[p[i]]]--;i++;}
}
int ans=0;
for(int i=1;i<=n-2;i++) ans=(ans^(i*p[i]));
printf("%lld\n",ans);
}
}
namespace Subtask2{
int fa[N],p[N],d[N];
inline void Solve(){
for(int i=1;i<=n-2;i++) read(p[i]),d[p[i]]++;
p[n-1]=n;
for(int i=1;i<=n;i++) d[i]++;
for(int i=1,j=1;i<=n-1;i++,j++){
while(d[j]!=1) j++;fa[j]=p[i];d[j]--;d[p[i]]--;
while(i<=n-1&&d[p[i]]==1&&p[i]<j){fa[p[i]]=p[i+1];d[p[i]]--;d[fa[p[i]]]--;i++;}
}
int ans=0;
for(int i=1;i<=n-1;i++) ans=(ans^(i*fa[i]));
printf("%lld\n",ans);
}
}
拉格朗日插值
inline ll ksm(ll a,ll b,ll mod){
ll res=1;
while(b){
if(b&1) (res*=a)%=mod;
a=a*a%mod;
b>>=1;
}
return res;
}
inline ll inv(ll a){
return ksm(a,mod-2,mod);
}
ll n,k,x[N],y[N],ans;
int main(){
read(n);read(k);
for(int i=1;i<=n;i++){
read(x[i]);read(y[i]);
}
for(int i=1;i<=n;i++){
ll fenzi=1,fenmu=1;
for(int j=1;j<=n;j++){
if(j==i) continue;
fenmu*=(x[i]-x[j]);fenmu%=mod;
fenzi*=(k-x[j]);fenzi%=mod;
}
ans+=y[i]*fenzi%mod*inv(fenmu)%mod;ans%=mod;
}
printf("%lld\n",(ans%mod+mod)%mod);
return 0;
}
- 需要把分母乘出来再求逆元,这样复杂度的瓶颈就不会是求逆元。
FWT 或卷积、和卷积、异或卷积
inline void FWT1(int *f,int n,int op){
for(int mid=1;mid<=(n>>1);mid<<=1)
for(int l=0;l<n;l+=(mid<<1))
for(int i=l;i<=l+mid-1;i++){
if(op==0){(f[i+mid]+=f[i])%=mod;}
else{(f[i+mid]-=f[i])%=mod;}
}
}
inline void FWT2(int *f,int n,int op){
for(int mid=1;mid<=(n>>1);mid<<=1)
for(int l=0;l<n;l+=(mid<<1))
for(int i=l;i<=l+mid-1;i++){
if(op==0){(f[i]+=f[i+mid])%=mod;}
else (f[i]-=f[i+mid])%=mod;
}
}
inline void FWT3(int *f,int n,int op){
for(int mid=1;mid<=(n>>1);mid<<=1)
for(int l=0;l<n;l+=(mid<<1))
for(int i=l;i<=l+mid-1;i++){
int a=f[i],b=f[i+mid];
if(op==0){f[i]=(a+b)%mod;f[i+mid]=(a-b)%mod;}
else{f[i]=1ll*((a+b)%mod)%mod*inv2%mod;f[i+mid]=1ll*((a-b)%mod)*inv2%mod;}
}
}
dsu on tree
inline void dfs2(int k,bool op){
for(int x=head[k];x;x=li[x].next){
int to=li[x].to;
if(to==fa[k]||to==son[k]) continue;
dfs2(to,0);
}
if(son[k]){dfs2(son[k],1);vis[son[k]]=1;}
Add(k);vis[son[k]]=0;
ans[k]=sum;
if(!op){Del(k);sum=0;maxx=0;}
}
set 维护凸包
inline void Insert(int id){
P now=p[id];
auto it=S.upper_bound(now);
auto Right=it;auto Left=(--it);
if(Cross(Subt((*Right),now),Subt((*Left),now))>=0) return;
nowans-=GetDis((*Left),(*Right));
while(it!=S.begin()){
auto a=it;it--;
if(Cross(Subt(now,(*a)),Subt((*it),(*a)))>=0){
nowans=nowans-GetDis((*a),(*it));
S.erase(a);
}
else break;
}
it=S.upper_bound(now);
while((it)!=--S.end()){
auto a=it;it++;
if(Cross(Subt((*it),(*a)),Subt(now,(*a)))>=0){
nowans=nowans-GetDis((*a),(*it));
S.erase(a);
}
else break;
}
it=S.upper_bound(now);
auto a=it,b=(--it);
nowans+=GetDis((*b),now)+GetDis(now,(*a));
S.insert(now);
}
求树上 k 级祖先
struct edge{
int to,next;
inline void Init(int to_,int ne_){
to=to_;next=ne_;
}
}li[N<<1];
int head[N],tail;
inline void Add(int from,int to){
li[++tail].Init(to,head[from]);
head[from]=tail;
}
int fa[N][21],Son[N],Dep[N],Deep[N],Top[N];
vector<int> u[N],d[N];
inline void dfs(int k,int fat){
fa[k][0]=fat;for(int i=1;i<=20;i++) fa[k][i]=fa[fa[k][i-1]][i-1];
Dep[k]=Dep[fat]+1;Deep[k]=Dep[k];
for(int x=head[k];x;x=li[x].next){
int to=li[x].to;
if(to==fat) continue;
dfs(to,k);Deep[k]=max(Deep[k],Deep[to]);
if(Deep[Son[k]]<Deep[to]) Son[k]=to;
}
}
inline void dfs2(int k,int t){
Top[k]=t;
if(k==t){
int len=Deep[k]-Dep[t];
d[k].push_back(k);int now=k;
for(int i=1;i<=len;i++){
now=Son[now];if(now==0) break;
d[k].push_back(now);
}
u[k].push_back(k);now=k;
for(int i=1;i<=len;i++){
now=fa[now][0];if(now==0) break;
u[k].push_back(now);
}
}
if(Son[k]) dfs2(Son[k],t);
for(int x=head[k];x;x=li[x].next){
int to=li[x].to;
if(to==fa[k][0]||to==Son[k]) continue;
dfs2(to,to);
}
}
uint s;
ll Ans;
inline uint get(uint x) {
x ^= x << 13;
x ^= x >> 17;
x ^= x << 5;
return s = x;
}
int n,q,root,ans,lg2[N];
inline void Ask(){
int x=((get(s)^ans)%n)+1;
int k=(get(s)^ans)%Dep[x];
// printf("x=%d k=%d\n",x,k);
if(k==0){ans=x;return;}
int nowx=fa[x][lg2[k]];int nowk=k-(1<<lg2[k]);
// printf("nowx=%d nowk=%d\n",nowx,nowk);
int t=Top[nowx],dep=Dep[nowx]-nowk;
// printf("t=%d dep=%d\n",t,dep);
// printf("Dep[t]=%d\n",Dep[t]);
if(dep>Dep[t]) ans=d[t][dep-Dep[t]];
else if(dep<=Dep[t]) ans=u[t][Dep[t]-dep];
}
KMP 从 0 开始
nxt[0]=-1;
for(int i=1,j=-1;i<len2;i++){
while(j>-1&&s2[i]!=s2[j+1]) j=nxt[j];
if(s2[i]==s2[j+1]) j++;
nxt[i]=j;
}
for(int i=0,j=-1;i<len1;i++){
while(j>-1&&(j==len1||s1[i]!=s2[j+1])) j=nxt[j];
if(s1[i]==s2[j+1]) j++;f[i]=j;
}
KMP 从 1 开始
for(int i=2,j=0;i<=len2;i++){
while(j>0&&s2[i]!=s2[j+1]) j=nxt[j];
if(s2[i]==s2[j+1]) j++;
nxt[i]=j;
}
for(int i=1,j=0;i<=len1;i++){
while(j>0&&(j==len1||s1[i]!=s2[j+1])) j=nxt[j];
if(s1[i]==s2[j+1]) j++;
f[i]=j;
}
EXKMP
int next[N],extend[N],lens,lent,ans;
char s[N],t[N];
inline void getnext(){
next[0]=lent;int now=0;
while(t[now]==t[1+now]&&now+1<lent) now++;
next[1]=now;
int p0=1;
for(int i=2;i<lent;i++){
if(i+next[i-p0]<next[p0]+p0) next[i]=next[i-p0];
else{
int now=next[p0]+p0-i;
now=Max(now,0);
while(t[now]==t[i+now]&&i+now<lent) now++;
next[i]=now;
p0=i;
}
}
}
inline void exkmp(){
getnext();
int now=0;
while(s[now]==t[now]&&now<Min(lens,lent)) now++;
extend[0]=now;
int p0=0;
for(int i=1;i<lens;i++){
if(i+next[i-p0]<extend[p0]+p0) extend[i]=next[i-p0];
else{
int now=extend[p0]+p0-i;
now=Max(now,0);
while(t[now]==s[i+now]&&now<lent&&now+i<lens) now++;
extend[i]=now;
p0=i;
}
}
}
在代码中是从 \(0\) 开始的,所以 \(i\) 相当于 \(k+1\) ,\(next_{i-p_0}\) 相当于 \(l\) ,\(extend_{p_0}+p_0\) 相当于 \(p\) ,\(extend_{p_0}+p_0-i\) 为上图 \(s\) 字符串中 \(k+1\) 到 \(p\) 的距离。
manacher
inline void Manacher(){
mid=0;maxright=0;
rep(i,1,n){
if(i<maxright) Len[i]=min(Len[(mid<<1)-i],maxright-i);else Len[i]=1;
while(i+Len[i]<=n&&i-Len[i]&&b[i+Len[i]]==b[i-Len[i]]) Len[i]++;
if(i+Len[i]>maxright) maxright=i+Len[i],mid=i;
}
}
//#a#a#a#
注意这里
len[(mid<<1)-i]
为 \(j\) ,这里len[mid]+mid-i
为 \(i\) 到最右边的距离。
在实际实现中,我们让 \(maxright\) 作为最右边字符在往右的字符,这样比较好写一点。
后缀数组
inline void Sort(){
for(int i=1;i<=n;i++) cnt[Rank[i]=s[i]]++;
for(int i=1;i<=m;i++) cnt[i]+=cnt[i-1];
for(int i=n;i>=1;i--) sa[cnt[Rank[i]]--]=i;
for(int w=1;;w<<=1,m=p){
p=0;for(int i=n;i>n-w;i--) id[++p]=i;
for(int i=1;i<=n;i++) if(sa[i]>w) id[++p]=sa[i]-w;
memset(cnt,0,sizeof(cnt));
for(int i=1;i<=n;i++) cnt[px[i]=Rank[id[i]]]++;
for(int i=1;i<=m;i++) cnt[i]+=cnt[i-1];
for(int i=n;i>=1;i--) sa[cnt[px[i]]--]=id[i];
memcpy(LastRank,Rank,sizeof(Rank));p=0;
for(int i=1;i<=n;i++) Rank[sa[i]]=Cmp(sa[i],sa[i-1],w)?p:++p;
if(p==n) break;
}
}
后缀数组求 height
inline void GetHeight(){
for(int i=1,k=0;i<=n;i++){
if(k) k--;
while(s[i+k]==s[sa[rk[i-1]-1]+k]) k++;
Height[rk[i]]=k;
}
}
FFT 与 NTT(非转置原理实现)
注意到换完之后的位置实际上是原来位置的二进制翻转。而二进制翻转我们可以 \(O(n)\) 的去做这个东西。
注意到我们可以在转移上加以优化,这样就避免了所有数组的复制操作。
inline void Gettr(int n){
for(int i=0;i<n;i++) tr[i]=(tr[i>>1]>>1)|((i&1)?(n>>1):0);
}
inline void fft(cp *f,bool flag){
for(int i=0;i<n;i++) if(i<tr[i]) swap(f[i],f[tr[i]]);
for(int p=2;p<=n;p<<=1){
int len=p>>1;
cp tg(cos(2*pi/p),sin(2*pi/p));
if(!flag) tg.y*=-1;
for(int k=0;k<n;k+=p){
cp buf(1,0);
for(int l=k;l<k+len;l++){
cp tt=buf*f[len+l];
f[len+l]=f[l]-tt;
f[l]=f[l]+tt;
buf=buf*tg;
}
}
}
}
inline void NTT(int *f,int len,int flag){
for(int i=0;i<len;i++) if(i<tr[i]) swap(f[i],f[tr[i]]);
for(int i=2;i<=len;i<<=1){
int tg=ksm(g,(mod-1)/i,mod),l=i>>1;
if(flag==-1) tg=ksm(tg,mod-2,mod);
for(int j=0;j<len;j+=i){
int buf=1;
for(int k=j;k<j+l;k++){
int tt=1ll*buf*f[k+l]%mod;
f[k+l]=((f[k]-tt)%mod+mod)%mod;
f[k]=(f[k]+tt)%mod;buf=1ll*buf*tg%mod;
}
}
}
if(flag==1) return;
int inv=ksm(len,mod-2,mod);for(int i=0;i<len;i++) f[i]=1ll*f[i]*inv%mod;
}
多项式求逆
inline void GetInv(int len,const int *a,int *b){
if(len==1){b[0]=ksm(a[0],mod-2,mod);return;}
GetInv((len+1)>>1,a,b);int m=1;while(m<(len<<1)) m<<=1;Gettr(m);
for(int i=0;i<len;i++) c[i]=a[i];for(int i=len;i<m;i++) c[i]=0;
NTT(c,m,1);NTT(b,m,1);
for(int i=0;i<m;i++) b[i]=1ll*(2-1ll*c[i]*b[i]%mod+mod)%mod*b[i]%mod;
NTT(b,m,-1);for(int i=len;i<m;i++) b[i]=0;Clear(c,m);
}//c is not clear
多项式除法
inline void GetDivi(int lena,int lenb,const int *a,const int *b,int *f,int *h){
int len=lena-lenb+1;int m=1;while(m<(len<<1)) m<<=1;
for(int i=0;i<lena;i++) A[i]=a[i];for(int i=0;i<lenb;i++) B[i]=b[i];
reverse(A,A+lena);reverse(B,B+lenb);
for(int i=len;i<lena;i++) A[i]=0;for(int i=len;i<lenb;i++) B[i]=0;
GetInv(len,B,d);Gettr(m);NTT(A,m,1);NTT(d,m,1);
for(int i=0;i<m;i++) f[i]=1ll*A[i]*d[i]%mod;NTT(f,m,-1);
for(int i=len;i<m;i++) f[i]=0;reverse(f,f+len);
for(int i=0;i<lena;i++) A[i]=a[i];for(int i=0;i<lenb;i++) B[i]=b[i];
m=1;while(m<(lenb+lena)) m<<=1;Gettr(m);
NTT(A,m,1);NTT(B,m,1);for(int i=0;i<len;i++) c[i]=f[i];for(int i=len;i<m;i++) c[i]=0;
NTT(c,m,1);for(int i=0;i<m;i++) h[i]=((A[i]-1ll*B[i]*c[i]%mod)%mod+mod)%mod;NTT(h,m,-1);
for(int i=lenb;i<m;i++) h[i]=0;
}//A,B,c,d is not clear
多项式开根
inline void GetSqrt(int len,const int *a,int *b){
if(len==1){b[0]=a[0];return;}
GetSqrt((len+1)>>1,a,b);int m=1;while(m<(len<<1)) m<<=1;
for(int i=0;i<len;i++) b[i]<<=1;
for(int i=0;i<m;i++) d[i]=0;GetInv(len,b,d);
for(int i=0;i<len;i++) b[i]>>=1;Gettr(m);
for(int i=0;i<len;i++) c[i]=a[i];for(int i=len;i<m;i++) c[i]=0;
NTT(c,m,1);NTT(c,m,1);NTT(b,m,1);
for(int i=0;i<m;i++) b[i]=1ll*(1ll*b[i]*b[i]%mod+c[i])%mod*d[i]%mod;
NTT(b,m,-1);
for(int i=len;i<m;i++) b[i]=0;
}//c,d is not clear
多项式 exp
inline void GetExp(int len,const int *a,int *b){
if(len==1){b[0]=1;return;}
GetExp((len+1)>>1,a,b);GetLn(len,b,C);
int m=1;while(m<(len<<1)) m<<=1;Gettr(m);
for(int i=0;i<len;i++) A[i]=a[i];for(int i=len;i<m;i++) A[i]=0;
NTT(b,m,1);NTT(C,m,1);NTT(A,m,1);
for(int i=0;i<m;i++) b[i]=(1ll*b[i]*((A[i]-C[i])%mod)%mod+b[i])%mod;
NTT(b,m,-1);for(int i=len;i<m;i++) b[i]=0;
for(int i=0;i<m;i++) C[i]=0;Clear(A,m);Clear(B,m);Clear(c,m);Clear(d,m);Clear(C,m);
}//A,B,c,d,C is not clear
多项式取 ln
inline void GetLn(int len,const int *a,int *b){
for(int i=1;i<len;i++) A[i-1]=1ll*a[i]*i%mod;
for(int i=0;i<len;i++) B[i]=a[i];GetInv(len,B,d);
int m=1;while(m<(len<<1)) m<<=1;NTT(A,m,1);NTT(d,m,1);
for(int i=0;i<m;i++) b[i]=1ll*A[i]*d[i]%mod;NTT(b,m,-1);
for(int i=len-1;i<m;i++) b[i]=0;
for(int i=len-1;i>=1;i--) b[i]=1ll*b[i-1]*ksm(i,mod-2,mod)%mod;
b[0]=0;Clear(A,m);Clear(B,m);Clear(c,m);Clear(d,m);
}//A,B,c,d, is not clear
Tarjan 求 scc
inline void Tarjan(int k){
dfn[k]=low[k]=++tot;sta[++top]=k;ins[k]=1;
for(int to:e[k]){
if(!dfn[to]){Tarjan(to);low[k]=min(low[k],low[to]);}
else if(ins[to]) low[k]=min(dfn[to],low[k]);
}
if(dfn[k]==low[k]){
int z;ctot++;do{z=sta[top--];vdcc[ctot].pb(z);c[z]=ctot;ins[z]=0;}while(z!=k);
}
}
线性基
struct LinearBasis{
int p[N];
inline void Insert(int x){
dec(i,0,49) if((x>>i)&1){
if(!p[i]){p[i]=x;return;}
else x^=p[i];
}
}
inline int Ask(){
int ans=0;
dec(i,0,49) if((ans^p[i])>ans) ans^=p[i];
return ans;
}
}lb;
左偏树
struct LeftHeap{
inline int Merge(int a,int b){
if(!a||!b) return a+b;if(p[b].v>p[a].v) swap(a,b);
rs(a)=Merge(rs(a),b);if(p[rs(a)].dist>p[ls(a)].dist) swap(rs(a),ls(a));
p[a].dist=p[rs(a)].dist+1;return a;
}
inline int Pop(int k){return Merge(ls(k),rs(k));}
}st;
自然数幂和拉格朗日插值部分
inline int Leg(int h){
sum=1;rep(i,1,k+2) sum=1ll*sum*(h-x[i])%mod;
rep(i,1,k+2) x[i]=sum*inv(h-x[i])%mod;
int ans=0;
rep(i,1,k+2){
ans=(ans+y[i]*x[i]%mod*invjie[i-1]%mod*invjie[k+2-i]%mod*(((k+2-i)&1)?(mod-1):1)%mod)%mod;
}
return ans;
}
李超树
struct Node{
int ls,rs,mx,mi;
}p[N];
int tot;
inline LCT(){tot=0;}
inline void ChangeMin(int &k,int l,int r,int z,int y,int id){
if(!k){k=++tot;assert(tot<=N-1);}
if(l==r){if(!p[k].mi||F(p[k].mi,l)>F(id,l)) p[k].mi=id;return;}int mid=(l+r)>>1;
if(z<=l&&r<=y){
if(!p[k].mi) p[k].mi=id;
if(F(p[k].mi,mid)>F(id,mid)) swap(p[k].mi,id);
(F(id,l)<F(p[k].mi,l))?ChangeMin(ls(k),l,mid,z,y,id):ChangeMin(rs(k),mid+1,r,z,y,id);
return;
}
if(z<=mid) ChangeMin(ls(k),l,mid,z,y,id);if(mid<y) ChangeMin(rs(k),mid+1,r,z,y,id);
}
inline void ChangeMax(int &k,int l,int r,int z,int y,int id){
if(!k){k=++tot;}
if(l==r){if(!p[k].mx||F(p[k].mx,l)<F(id,l)) p[k].mx=id;return;}int mid=(l+r)>>1;
if(z<=l&&r<=y){
if(!p[k].mx) p[k].mx=id;
if(F(p[k].mx,mid)<F(id,mid)) swap(p[k].mx,id);
(F(id,l)>F(p[k].mx,l))?ChangeMax(ls(k),l,mid,z,y,id):ChangeMax(rs(k),mid+1,r,z,y,id);
return;
}
if(z<=mid) ChangeMax(ls(k),l,mid,z,y,id);if(mid<y) ChangeMax(rs(k),mid+1,r,z,y,id);
}
inline void Change(int &k,int l,int r,int z,int y,int id){
ChangeMin(k,l,r,z,y,id);ChangeMax(k,l,r,z,y,id);
}
inline int AskMin(int k,int l,int r,int w){
if(!k) return 0;if(l==r) return p[k].mi;
int mid=(l+r)>>1;int id=-1;
if(w<=mid) id=AskMin(ls(k),l,mid,w);else id=AskMin(rs(k),mid+1,r,w);
if(id==0) return p[k].mi;
return (F(id,w)<F(p[k].mi,w))?id:p[k].mi;
}
inline int AskMax(int k,int l,int r,int w){
if(!k) return 0;if(l==r) return p[k].mx;
int mid=(l+r)>>1;int id=-1;
if(w<=mid) id=AskMax(ls(k),l,mid,w);else id=AskMax(rs(k),mid+1,r,w);
if(id==0) return p[k].mx;
return (F(id,w)>F(p[k].mx,w))?id:p[k].mx;
}
inline void Clear(){mset(p,0);rt=0;tot=0;}