专辑:知识整理
一、并查集
(1) 查找公共祖先
int getfa(int k){
return k==fa[k]?fa[k]:fa[k]=getfa(fa[k]);
}
(2) 合并
x=getfa(x),y=getfa(y);
if (x!=y) fa[xx]=yy;
(3) 判断是否在同一个集合
bool check(int a,int b){
return(getfa(a)==getfa(b));
}
二、线性筛素数
f[1]=0;
for (int i=2;i<=MAXX;i++)
if (f[i])
for (int j=1;j<=maxx/i;j++)
f[i*j]=1;
三、高精度
(1) 高精度加法
int a[MAXX],b[MAXX];
cin>>s1>>s2;
for (int i=1;i<=s1.size();i++) a[i]=s1[s1.size()-i]-48;
for (int i=1;i<=s2.size();i++) b[i]=s2[s2.size()-i]-48;
int c[MAXX];
memset(c,0,sizeof(c));
int len=max(s1.size(),s2.size());
for (int i=1;i<=len;i++){
c[i]+=a[i]+b[i];
c[i+1]=c[i]/10;
c[i]%=10;
}
int k=MAXX-1;
while (!c[k]&&k>1) k--;
for (int i=k;i>=1;i--) cout<<c[i];
(2) 高精度减法
int a[MAXX],b[MAXX];
cin>>s1>>s2;
if (s1比s2小) cout<<'-',swap(s1,s2);
for (int i=1;i<=s1.size();i++) a[i]=s1[s1.size()-i]-48;
for (int i=1;i<=s2.size();i++) b[i]=s2[s2.size()-i]-48;
int c[MAXX];
memset(c,0,sizeof(c));
int len=max(s1.size(),s2.size());
for (int i=1;i<=len;i++){
c[i]+=a[i]-b[i];
if (c[i]<0) c[i]+=10,c[i+1]-=1;
}
int k=MAXX-1;
while (!c[k]&&k>1) k--;
for (int i=k;i>=1;i--) cout<<c[i];
(3) 高精度乘法
int a[MAXX],b[MAXX];
cin>>s1>>s2;
for (int i=1;i<=s1.size();i++) a[i]=s1[s1.size()-i]-48;
for (int i=1;i<=s2.size();i++) b[i]=s2[s2.size()-i]-48;
int c[MAXX];
memset(c,0,sizeof(c));
int len1=s1.size(),len2=s2.size();
for (int i=1;i<=len1;i++)
for (int j=1;j<=len2;j++){
c[i+j-1]+=a[i]*b[j];
c[i+j]+=c[i+j-1]/10;
c[i+j-1]%=10;
}
int k=MAXX-1;
while (!c[k]&&k>1) k--;
for (int i=k;i>=1;i--) cout<<c[i];
(4) 高精度除法
int a[MAXX],b[MAXX];
string s;
long long c;
cin>>s;
cin>>c;
for (int i=1;i<=s.size();i++) a[i]=s[i-1]-48;
int len=s.size();
int k=0;
for (int i=1;i<=len;i++){
k=k*10+a[i];
b[i]=k/c;
k%=c;
}
k=1;
while (k<len&&!b[k]) k++;
for (int i=k;i<=len;i++) cout<<b[i];
四、图论
(1) 建图
void insert(int xx,int yy,int zz){
e[++len].next=linkk[xx];
linkk[xx]=len;
e[len].y=yy;
e[len].v=vv;
}
(2) 遍历
voi dfs(int x){
vis[x]=1;
for (int i=linkk[x];i;i=e[i].next)
if (!vis[e[i].y]) dfs(e[i].y);
}
(3) 最短路
①dijistra
I:不用堆优化
for (int i=1;i<=n;i++) dis[i]=a[st][i];
memset(vis,0,sizeof(vis));
vis[st]=1;dis[st]=0;
for (int _=1;_<n;_++){
int min=MAXX,mini;
for (int i=1;i<=n;i++)
if (!vis[i]&&dis[i]<minn) minn=dis[i],mini=i;
if (!k)break;
vis[k]=1;
for (int i=1;i<=n;i++)
if (!vis[i]&&dis[i]>dis[mini]+a[mini][i]) dis[i]=dis[mini]+a[mini][i];
}
II:用堆优化
typedef pair < int , int > pii;
priority_queue < pii,vector<pii>,greater<pii> > q;
memset(dis,20,sizeof(dis));
dis[1]=0;
q.push(make_pair(0,1));
while (!q.empty()){
pii t=q.top();q.pop();
int x=t.second,vv=t.first;
if (vis[x]) continue;
vis[x]=1;
for (int i=linkk[x];i;i=e[i].next)
if (dis[e[i].y]>vv+e[i].v)
dis[e[i].y]=vv+e[i].v,q.push(make_pair(dis[e[i].y],e[i].y));
}
②、SPFA
memset(vis,0,sizeof(vis));
queue < int > q;
q.push(st);
dis[st]=0;
vis[st]=1;
while (!q.empty()){
int x=q.front();q.pop();
vis[x]=0;
for (int i=linkk[x];i;i=e[i].next)
if (dis[e[i].y]>dis[x]+e[i].v){
dis[e[i].y]=dis[x]+e[i].v;
if (!vis[e[i].y]) q.push(e[i].y),vis[e[i].y]=1;
}
}
③ floyed
for (int k=1;k<=n;k++)
for (int i=1;i<=n;i++)
for (int j=1;j<=n;j++)
dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);
(4) 最小生成树
① Kruskal
sort(e+1,e+len+1,mycmp(x.v<y.v));
for (int i=1;i<=len;i++){
int x=getfa(e[i].x),y=getfa(e[i].y);
if (x!=y) fa[x]=y,ans+=e[i].v;
}
cout<<ans;
②Prim
void Prim(){
int now=1;
memset(dis,20,sizeof(dis));
for (int i=linkk[1];i;i=e[i].next) dis[e[i].y]=min(dis[e[i].y],e[i].v);
for (int _=1;_<n;_++){
int minn=MAXX;
vis[now]=1;
for (int i=1;i<=n;i++)
if (!vis[i]&&minn>dis[i]) minn=dis[i],now=i;
ans+=minn;
for (int i=linkk[now];i;i=e[i].next)
if (!vis[e[i].y]&&dis[e[i].y]>e[i].v)
dis[e[i].y]=e[i].v;
}
}
五、二分答案:
int l=1,r=MAXX;
while (l+1<r){
int mid=(l+r)>>1;
if (check(mid)) l=mid;
else r=mid;
}
printf("%d\n",check(l)?l:r);
六、背包
(1) 0/1 背包
for (int i=1;i<=n;i++)
for (int j=a[i];j<=w;j++)
dp[j]=max(dp[j],dp[j-a[i]]+v[i]);
(2)完全背包
for (int i=1;i<=n;i++)
for (int j=w;j>=a[i];j--)
dp[j]=max(dp[j],dp[j-a[i]]+v[i]);
(3) 多重背包
int w[MAXX];//原来的体积
int v[MAXX];//原来的价值
int w_[MAXX];//二进制分解后的体积
int v_[MAXX];//二进制分解后的价值
int tot=0;
for (int i=1;i<=n;i++){
scanf("%d %d %d",&m[i],&w[i],&v[i]);
int tmp=1;
while (m[i]-tmp>=0){
m[i]-=tmp;
w_[++tot]=tmp*w[i];
v_[tot]=tmp*v[i];
tmp*=2;
}
if (m[i]>0) w_[++tot]=w[i]*m[i],v_[tot]=v[i]*m[i];
}
for (int i=1;i<=tot;i++)
for (int j=v;j>=w_[i];j--)
dp[j]=max(dp[j],dp[j-w_[i]]+v_[i]);
(4) 混合背包
if (这是0/1 背包){(1)}
else if (这是完全背包) {(2)}
else if (这是多重背包) {(3)}
(5) 分组背包
for (int k=1;k<=K;k++)//枚举组数
for (int j=w;j>=0;j--)//体积
for (int i=1;i<=kk[k];i++)//枚举在第k组里的物品
if (c>=w[i]) dp[j]=max(dp[j],dp[k-w[i]]+v[i]);
(6) 二维费用背包
for (int i=1;i<=n;i++)
for (int j=a[i];j<=w;j++)
for (int k=b[i];k<=w_;k++)
dp[j][k]=min(dp[j][k],dp[j-a[i]][k-b[i]]+v[i]);
七、动态规划
(1) LIS(最长上升子序列)
f[0]=0;
for (int i=1;i<=n;i++){
for (int j=1;j<i;j++)
if (a[j]>=a[i]&&f[j]>f[i])
f[i]=f[j];
f[i]++;
maxx=max(maxx,f[i]);
}
(2) LCS(最长公共子序列)
for (int i=1;i<=n;i++)
for (int j=1;j<=m;j++)
if (a[i]==b[j]) f[i][j]=max(f[i][j],f[i-1][j-1]+1);
else f[i][j]=max(f[i][j-1],f[i-1][j]);