CSP/NOIP 之前还需要学/复习的东西
主要是复习。
当然可能能会发现自己之前学假了然后重学的。
图论类
- 割点
void tarjan(int u,int fa){
vis[u]=1;int chi=0;//统计孩子数量
dfn[u]=low[u]=++cnt;
for(int i=head[u];i;i=e[i].nxt){
int to=e[i].to;
if(!vis[to]){
chi++;tarjan(to,u);
low[u]=min(low[to],low[u]);
if(fa!=u&&low[to]>=dfn[u]&&!flag[u]){//第一个依据
flag[u]=1;
res++;//割点数量
}
}
else if(to!=fa)
low[u]=min(low[u],dfn[to]);
}
if(fa==u&&chi>=2&&!flag[u]){//第二个依据
flag[u]=1;res++;
}
}
- 桥
void tarjan(int u,int fat){
fa[u]=fat;
low[u]=dfn[u]=++cnt;
for(int i=head[u];i;i=e[i].nxt){
int v=e[i].to;
if(!dfn[v]){
tarjan(v,u);low[u]=min(low[u],low[v]);
if(low[v]>dfn[u]){vis[v]=true;++bri;}//bri 是割边的数量
}
else if(dfn[v]<dfn[u]&&v!=fat)
low[u]=min(low[u],dfn[v]);
}
}
数据结构类
- 哈夫曼树
struct node{
int w,h;
bool operator < (const node &a) const{
return a.w==w?h>a.h:w>a.w;
}
};
signed main(){
n=read();k=read();
priority_queue<node> q;
for(int i=1,w;i<=n;i++)
w=read(),q.push((node){w,1});
while((q.size()-1)%(k-1))
q.push((node){0,1});
while(q.size()>=k){
int h=-1,w=0;
for(int i=1;i<=k;i++){
node t=q.top();q.pop();
h=max(h,t.h);w+=t.w;
}
ans+=w;
q.push((node){w,h+1});
}
printf("%lld\n%lld\n",ans,q.top().h-1);
return 0;
}
- 左偏树
namespace LIT{
#define ls lson[x]
#define rs rson[x]
bool vis[maxn];
int fa[maxn],dis[maxn];
int lson[maxn],rson[maxn];
struct node{
int pos,val;
bool operator < (const node &b) const{
return val^b.val?val<b.val:pos<b.pos;
}
}v[maxn];
int findf(int x){
return fa[x]==x?x:fa[x]=findf(fa[x]);
}
int merge(int x,int y){
if(!x||!y) return x+y;
if(v[y]<v[x]) swap(x,y);
rs=merge(rs,y);
if(dis[ls]<dis[rs])swap(ls,rs);
dis[x]=dis[rs]+1;
return x;
}
}
- 笛卡尔树
signed main(){
n=read();
for(int i=1,k;i<=n;i++){
a[i]=read();k=top;
while(k&&a[zhan[k]]>a[i]) k--;
if(k) rs[zhan[k]]=i;
if(k<top) ls[i]=zhan[k+1];
zhan[++k]=i;top=k;
}
for(int i=1;i<=n;i++)ans1^=(i*(ls[i]+1));
for(int i=1;i<=n;i++)ans2^=(i*(rs[i]+1));
printf("%lld %lld\n",ans1,ans2);
return 0;
}
- 主席树
//静态区间第 k 小
#define ls(x) t[x].ls
#define rs(x) t[x].rs
int n,m,all,cnt;
int a[maxn],b[maxn],rt[maxn];
struct node{int siz,ls,rs;}t[maxn];
void insert(int last,int &now,int l,int r,int pos){
if(!now) now=++cnt;
t[now].siz=t[last].siz+1;
if(l==r) return;int mid=l+r>>1;
if(pos<=mid) t[now].rs=t[last].rs,insert(t[last].ls,t[now].ls,l,mid,pos);
else t[now].ls=t[last].ls,insert(t[last].rs,t[now].rs,mid+1,r,pos);
}
int query(int last,int now,int l,int r,int val){
if(l==r) return l;
int lef=t[ls(now)].siz-t[ls(last)].siz;
int mid=l+r>>1;
if(val>lef) return query(t[last].rs,t[now].rs,mid+1,r,val-lef);
else return query(t[last].ls,t[now].ls,l,mid,val);
}
int main(){
n=read();m=read();
for(int i=1;i<=n;i++)b[i]=a[i]=read();
sort(b+1,b+n+1);all=unique(b+1,b+n+1)-b-1;
for(int i=1;i<=n;i++)a[i]=lower_bound(b+1,b+all+1,a[i])-b;
for(int i=1;i<=n;i++) insert(rt[i-1],rt[i],1,all,a[i]);
for(int i=1,fr,to,val;i<=m;i++){
fr=read();to=read();val=read();
printf("%d\n",b[query(rt[fr-1],rt[to],1,all,val)]);
}
return 0;
}
- 各种平衡树(不在大纲中,但是会了总比不会好)
namespace Treap{
int insert(int x){
val[++all]=x;
dat[all]=rand();
sum[all]=cnt[all]=1;
return all;
}
void pushup(int x){
sum[x]=sum[ch[x][0]]+sum[ch[x][1]]+cnt[x];
}
void build(){
root=insert(-INF);
ch[root][1]=insert(INF);
pushup(root);
}
void rotate(int &x,int son){
int tmp=ch[x][son^1];
ch[x][son^1]=ch[tmp][son];
ch[tmp][son]=x;x=tmp;
pushup(ch[x][son]);
pushup(x);
}
void push(int &x,int v){
if(!x) {x=insert(v);return;}
if(v==val[x]) cnt[x]++;
else{
int son=v<val[x]?0:1;push(ch[x][son],v);
if(dat[x]<dat[ch[x][son]]) rotate(x,son^1);
}
pushup(x);
}
void Remove(int &x,int v){
if(!x) return;
if(v==val[x]){
if(cnt[x]>1) {cnt[x]--,pushup(x);return;}
if(ch[x][0]||ch[x][1]){
if(!ch[x][1]||dat[ch[x][0]]>dat[ch[x][1]])
rotate(x,1),Remove(ch[x][1],v);
else rotate(x,0),Remove(ch[x][0],v);
pushup(x);
}
else x=0;return;
}
v<val[x]?Remove(ch[x][0],v):Remove(ch[x][1],v);
pushup(x);
}
int getrank(int x,int v){
if(!x) return -2;
if(v==val[x]) return sum[ch[x][0]]+1;
if(v<val[x]) return getrank(ch[x][0],v);
return sum[ch[x][0]]+cnt[x]+getrank(ch[x][1],v);
}
int getval(int x,int rank){
if(!x) return INF;
if(rank<=sum[ch[x][0]]) return getval(ch[x][0],rank);
if(rank<=sum[ch[x][0]]+cnt[x]) return val[x];
return getval(ch[x][1],rank-sum[ch[x][0]]-cnt[x]);
}
int getpre(int v){
int now=root,pre;
while(now){
if(val[now]<v) pre=val[now],now=ch[now][1];
else now=ch[now][0];
}
return pre;
}
int getnxt(int v){
int now=root,nxt;
while(now){
if(val[now]>v) nxt=val[now],now=ch[now][0];
else now=ch[now][1];
}
return nxt;
}
}
- ST表
//静态区间最大值
int n,m,a[maxn],Max[maxn][30],l,r;
int Query(int lef,int rig){
int k=log2(rig-lef+1);
return max(Max[lef][k],Max[rig-(1<<k)+1][k]);
}
int main(){
n=read();m=read();
for(int i=1;i<=n;i++) scanf("%d",&Max[i][0]);
for(int j=1;j<=30;j++)
for(int i=1;i+(1<<j)-1<=n;i++)
Max[i][j]=max(Max[i][j-1],Max[i+(1<<(j-1))][j-1]);
for(int i=1;i<=m;i++){
scanf("%d%d",&l,&r);
printf("%d\n",Query(l,r));
}
return 0;
}
数论类
- BSGS
//a^l % Mod = b 求最小非负整数 l(Mod 是质数)
int BSGS(int a,int b,int Mod,int &ret){
a%=Mod;b%=Mod;
if(!a){if(!b){ret=1;return 1;}else return 0;}
int m=ceil(sqrt(Mod));map<int,int> h;
for(int i=0,tmp=b%Mod;i<=m;i++,tmp=tmp*a%Mod) h[tmp]=i;
a=quickpow(a,m,Mod);
for(int i=1,tmp=a%Mod;i<=m;i++,tmp=tmp*a%Mod)
if(h.count(tmp)){ret=i*m-h[tmp];return 1;}
return 0;
}
- CRT,EXCRT
//CRT
void exgcd(int a,int b,int &x,int &y){
if(b==0){x=1;y=0;return;}
exgcd(b,a%b,x,y);
int z=x;x=y;y=z-y*(a/b);
}
signed main(){
n=read();
for(int i=1;i<=n;i++)
a[i]=read(),b[i]=read(),M*=a[i];
for(int i=1;i<=n;i++){
times[i]=M/a[i];
int x=0;int y=0;
exgcd(times[i],a[i],x,y);
ans+=b[i]*times[i]*(x<0?x+a[i]:x);
}
cout<<ans%M;
return 0;
}
//EXCRT
signed main(){
n=read();
int Ans,M,x,y;
for(rr int i=1;i<=n;i++)
m[i]=read(),a[i]=read();
M=m[1],Ans=a[1];
for(int i=2,A,B,C;i<=n;i++){
A=M,B=m[i],C=(a[i]-Ans%B+B)%B;
int now=exgcd(A,B,x,y),f=B/now;
x=quicktimes(x,C/now,f);
Ans+=x*M;M*=f;Ans=(Ans%M+M)%M;
}
printf("%lld\n",Ans);
}
return 0;
}
- 拉格朗日插值(朴素)
signed main(){
n=read();k=read();
for(int i=1;i<=n;i++)
x[i]=read(),y[i]=read();
for(int i=1,fir,sec;i<=n;i++){
fir=y[i]%Mod,sec=1;
for(int j=1;j<=n;j++){
if(i==j) continue;
fir=fir*(k-x[j])%Mod;
sec=sec*(x[i]-x[j])%Mod;
}
Ans=(Ans+(fir*quickpow(sec,Mod-2)%Mod)+Mod)%Mod;
}
printf("%lld\n",Ans);
return 0;
}
- 拉格朗日插值(自变量取值连续时)
signed main(){
n=read();k=read();pre[0]=fac[0]=suf[k+3]=1;
for(int i=k+2;i>=1;i--)suf[i]=suf[i+1]*(n-i)%Mod;
for(int i=1;i<=k+2;i++)
fac[i]=fac[i-1]*i%Mod,pre[i]=pre[i-1]*(n-i)%Mod;
for(int i=1,fir,sec;i<=k+2;i++){
tmp=(tmp+quickpow(i,k))%Mod;
fir=pre[i-1]*suf[i+1]%Mod;
sec=fac[i-1]*((k-i)&1?-1:1)*fac[k+2-i]%Mod;
ans=((ans+tmp*fir%Mod*quickpow(sec,Mod-2)%Mod)%Mod+Mod)%Mod;
}
printf("%lld\n",ans);
return 0;
}
- 高斯消元
int main(){
n=read();
for(int i=1;i<=n;i++)
for(int j=1;j<=n+1;j++)
scanf("%lf",&Gu[i][j]);
for(int i=1,Max;i<=n;i++){
Max=i;
for(int j=i+1;j<=n;j++)
if(fabs(Gu[j][i])>fabs(Gu[Max][i]))Max=j;
for(int j=1;j<=n+1;j++) swap(Gu[i][j],Gu[Max][j]);
if(!Gu[i][i]) {printf("No Solution\n");return 0;}
for(int j=1;j<=n;j++){
if(j==i) continue;double tmp=Gu[j][i]/Gu[i][i];
for(int k=i+1;k<=n+1;k++) Gu[j][k]-=Gu[i][k]*tmp;
}
}
for(int i=1;i<=n;i++) printf("%.2lf\n",Gu[i][n+1]/Gu[i][i]);
return 0;
}
- 各种定理
字符串类
- Trie
struct Trie{
int Nxt[maxn][15],tot;
void Insert(char *s){
int u=0;
for(int i=1;s[i];i++){
if(!Nxt[u][s[i]]) Nxt[u][s[i]]=++tot;
u=Nxt[u][s[i]];
}
}
int Find(char *s){
int p=0,len=strlen(s+1);
if(Judge[s+1]) return Get[s+1];
memset(vis,false,sizeof vis);vis[0]=true;
for(int i=0;i<=len;i++){
if(!vis[i]) continue;cnt=i;
for(int j=i+1;j<=len;j++){
int c=s[j]-'a';
p=Nxt[p][c];if(!p) break;
if(flag[p]) vis[j]=true;
}
}
Judge[s+1]=true;Get[s+1]=cnt;
return cnt;//能匹配到的最长前缀长度
}
}trie;
- AC自动机
namespace Automaton{
int Nxt[maxn][30],Fail[maxn];
int tot,e[maxn];queue<int> q;
void Insert(char *s){
int u=0;
for(int i=1;s[i];i++){
if(!Nxt[u][s[i]-'a']) Nxt[u][s[i]-'a']=++tot;
u=Nxt[u][s[i]-'a'];
}
e[u]++;
}
void Build(){
for(int i=0;i<26;i++)
if(Nxt[0][i]) q.push(Nxt[0][i]);
while(!q.empty()){
int u=q.front();q.pop();
for(int i=0;i<26;i++){
if(Nxt[u][i]) Fail[Nxt[u][i]]=Nxt[Fail[u]][i],q.push(Nxt[u][i]);
else Nxt[u][i]=Nxt[Fail[u]][i];
}
}
}
int Query(char *s){
int u=0,ans=0;
for(int i=1;s[i];i++){
u=Nxt[u][s[i]-'a'];
for(int j=u;j&&e[j]!=-1;j=Fail[j]){//
ans+=e[j],e[j]=-1;
}
}
return ans;
}
}
- KMP,EXKMP
//KMP
Kmp[0]=Kmp[1]=0;
int n=strlen(A+1),m=strlen(B+1);
for(int i=1;i<m;i++){
while(j&&B[j+1]!=B[i+1]) j=Kmp[j];
if(B[i+1]==B[j+1]) j++,Kmp[i+1]=j;
}
j=0;
for(i=0;i<n;i++){
while(j&&B[j+1]!=A[i+1]) j=Kmp[j];
if(B[j+1]==A[i+1]) ++j;
if(j==m) printf("%d\n",i+2-m),j=Kmp[j];
}
//EXKMP
void Getnxt(){
nxt[0]=m;int now=0,p0=1;
while(t[now]==t[1+now]&&now+1<m) now++;
nxt[1]=now;
for(int i=1;i<m;i++){
if(i+nxt[i-p0]<nxt[p0]+p0) nxt[i]=nxt[i-p0];
else{
int now=p0+nxt[p0]-i;now=max(now,0*1ll);
while(now+i<m&&t[now]==t[now+i]) now++;
nxt[i]=now;p0=i;
}
}
}
void Exkmp(){
Getnxt();int now=0,p0=0;
while(s[now]==t[now]&&now<m&&now<n) now++;
extend[0]=now;
for(int i=1;i<n;i++){
if(i+nxt[i-p0]<extend[p0]+p0) extend[i]=nxt[i-p0];
else{
int now=extend[p0]+p0-i;now=max(now,0*1ll);
while(t[now]==s[now+i]&&now<m&&now+i<n) now++;
extend[i]=now;p0=i;
}
}
}
- 后缀数组(朴素)
bool cmp(int x,int y){
return rk[x]^rk[y]?rk[x]<rk[y]:rk[x+w]<rk[y+w];
}
int main(){
scanf("%s",s+1);n=strlen(s+1);
for(int i=1;i<=n;i++)sa[i]=i,rk[i]=s[i];
for(w=1;w<n;w<<=1){
sort(sa+1,sa+n+1,cmp);
for(int i=1;i<=n;i++)oldrk[i]=rk[i];
for(int i=1,p=0;i<=n;i++){
if(oldrk[sa[i]]==oldrk[sa[i-1]]&&
oldrk[sa[i]+w]==oldrk[sa[i-1]+w])
rk[sa[i]]=p;
else rk[sa[i]]=++p;
}
}
for(int i=1;i<=n;i++) printf("%d ",sa[i]);
return 0;
}
- manacher
void build(){
scanf("%s",c+1);n=strlen(c+1);
s[++cnt]='~',s[++cnt]='#';
for(int i=1;i<=n;i++)
s[++cnt]=c[i],s[++cnt]='#';
s[++cnt]='!';
}
void work(){
for(int i=2;i<=cnt-1;i++){
if(i<=mr) p[i]=min(p[mid*2-i],mr-i+1);
else p[i]=1;while(s[i-p[i]]==s[i+p[i]]) p[i]++;
if(i+p[i]>mr)mr=i+p[i]-1,mid=i;Ans=max(Ans,p[i]);
}
}
int main(){
build();work();
printf("%d\n",Ans-1);
return 0;
}
动态规划类
- 状压、区间、树形、数位、背包等,基本都看。
其他的
不知道怎么分类的知识点。
- 各种排序(基数排序,归并排序,锦标赛排序等)
//基数排序
inline void Radixsort(){
for(rr int i=1;i<256;i++) cnt[i]=0;
for(rr int i=1;i<=n;i++) ++cnt[a[i]&255];
for(rr int i=1;i<256;i++) cnt[i]+=cnt[i-1];
for(rr int i=n;i>=1;i--) b[cnt[a[i]&255]--]=a[i];
for(rr int i=1;i<256;i++) cnt[i]=0;
for(rr int i=1;i<=n;i++) ++cnt[b[i]>>8&255];
for(rr int i=1;i<256;i++) cnt[i]+=cnt[i-1];
for(rr int i=n;i>=1;i--) a[cnt[b[i]>>8&255]--]=b[i];
for(rr int i=1;i<256;i++) cnt[i]=0;
for(rr int i=1;i<=n;i++) ++cnt[a[i]>>16&255];
for(rr int i=1;i<256;i++) cnt[i]+=cnt[i-1];
for(rr int i=n;i>=1;i--) b[cnt[a[i]>>16&255]--]=a[i];
for(rr int i=1;i<256;i++) cnt[i]=0;
for(rr int i=1;i<=n;i++) ++cnt[b[i]>>24&255];
for(rr int i=1;i<256;i++) cnt[i]+=cnt[i-1];
for(rr int i=n;i>=1;i--) a[cnt[b[i]>>24&255]--]=b[i];
}
//归并排序
void Merge(int l,int r){
if(r-l<=1) return;
int mid=l+(r-l>>1);
Merge(l,mid);Merge(mid,r);
int p=l,q=mid,s=l;
while(s<r){
if(p>=mid||(q<r&&a[p]>a[q])){
t[s++]=a[q++];//cnt+=mid-p;
}
else t[s++]=a[p++];
}
for(int i=l;i<r;i++) a[i]=t[i];
}
//锦标赛排序
int winner(int pos1,int pos2){
int fr=pos1>=n?pos1:tmp[pos1];
int to=pos2>=n?pos2:tmp[pos2];
return tmp[fr]<=tmp[to]?fr:to;
}
void build(int &v){
for(int i=0;i<n;i++)tmp[n+i]=a[i];
for(int i=2*n-1,k,j;i>1;i-=2)
k=i/2,j=i-1,tmp[k]=winner(i,j);
v=tmp[tmp[1]];tmp[tmp[1]]=INF;
}
void rebuild(int &v){
int i=tmp[1];
while(i>1){
int j,k=i/2;
if(!(i%2)&&i<2*n-1) j=i+1;
else j=i-1;tmp[k]=winner(i,j);
i=k;
}
v=tmp[tmp[1]];
tmp[tmp[1]]=INF;
}
void TournamentSort(){
int v;build(v);
for(int i=0;i<n;i++)
a[i]=v,rebuild(v);
}
- 线性基
void insert(int k){
for(int i=len;i>=0;i--){
if(!(k&(1ll<<i))) continue;
if(!p[i]){p[i]=k;return;}
k^=p[i];
}
}
signed main(){
n=read();
for(int i=1;i<=n;i++) insert(read());
for(int i=len;i>=0;i--) ans=max(ans,(ans^p[i]));
printf("%lld\n",ans);
return 0;
}
- 各种 STL