ε=(´ο`*))) 这些笔记集合什么的要是其他大佬来csdn写绝对写的远超于我qwq,分析也更加深刻,蒟蒻在此瑟瑟发抖,临近考试将自己会的不会的旧的新学的知识稍微罗列出来。因为是蒟蒻嘛,文章择优而取,有错误请指出,不胜感激qwq
内容稍长稍多,也是择其喜好而取吧w

那么大致来个索引先:

文章目录

  • ===基础算法===
    • 滚动数组
    • 尺取法
    • 分治
    • 堆排序
    • 双向宽搜
    • 高精家族
    • 归并排序+求逆序对
    • 手读手输(快读)
  • ===动态规划===
    • 背包
    • 划分型
    • 区间型
    • 状压型
    • 树型
    • 棋盘型
    • 递推型
  • ===数论===
    • 快速幂
    • 反素数
    • 筛法
    • gcd系列
    • 费马小定理
    • CRT
    • 矩阵系列
    • 组合数学
    • 分解质因数
    • 数学规律推理
  • ===图论===
    • 最短路(有权图)
    • 最短路(无权图)
    • 二分图染色
    • 第K短路
    • 差分约束
    • 并查集
    • 最小生成树
    • 拓扑排序
    • LCA
    • tarjan
  • ===数据结构===
    • 哈希
    • 线段树
    • 扫描线算法
    • 二维前缀和
    • 栈/队列
    • 图的遍历(BFS版)
    • 树链剖分
  • ====字符串====
    • Kmp
  • ====其他算法====
    • 随机化
    • STL大法

=基础算法=

滚动数组

新学的姿势,详情参见
http://blog.csdn.net/qq_36693514/article/details/78279869
滚动数组笔记

char ch[100010];
int f[5][4][4][4][4],ans,n;//第一维滚动起来
int main(){memset(f,-1,sizeof(f));f[0][0][0][0][0]=0;read(n);scanf("%s",ch);for(ri i=0;i<n;i++)//这里的枚举次数不变for(ri a1=0;a1<=3;a1++)for(ri a2=0;a2<=3;a2++)for(ri b1=0;b1<=3;b1++)for(ri b2=0;b2<=3;b2++){ri x=i%4,y=(i+1)%4;//在这里%下...}for(ri a1=0;a1<=3;a1++)for(ri a2=0;a2<=3;a2++)for(ri b1=0;b1<=3;b1++)for(ri b2=0;b2<=3;b2++)ans=max(ans,f[n%4][a1][a2][b1][b2]);//最后输出时printf("%d",ans);return 0;
}

尺取法

题目:http://blog.csdn.net/consciousman/article/details/52348439
题解 http://blog.csdn.net/qq_36693514/article/details/78320753

LL sum,s,qu[100010];
int i,j,n,t,ans=inf;
int main(){cin>>t;while(t--){cin>>n>>s;for(i=0;i<n;++i) cin>>qu[i];int l=0,r=0;ans=inf,sum=0;while(1){while (r<n && sum<s) sum += qu[r++];  if (sum < s) break;  ans = min(ans,r-l);  sum -= qu[l++];  }if(ans==inf) ans=0;cout<<ans<<'\n';}
}

分治

double a,b,c,d,x,x1,x2;
double f(double x){return (x*x*x*a+b*x*x+c*x+d);}
int main(){cin>>a>>b>>c>>d;for (x=-10000;x<=10000;x++){x1=(x-0.05)/100;x2=(x+0.05)/100;if (f(x1)*f(x2)<0||f(x1)==0) printf("%.2f ",x/100); }
}

堆排序

这里是小根堆排序,更改下重载即可实现大根堆

struct ed{int num;
};
bool operator < (ed a,ed b){return a.num > b.num;}
priority_queue<ed>q;
int main(){ed x;int n;rd(n);for(ri i=1;i<=n;++i){rd(x.num);q.push(x);}while(!q.empty()){printf("%d ",q.top());q.pop();}
}

双向宽搜

eg:迷宫
根据实验测得下列结论:
耗时最长:调用队列
耗时次之:手写队列
耗时最短:双向宽搜
双向宽搜可是个好东西,能够将搜索的时间复杂度指数级的降低,做到218–>29

struct ed{int x,y;
}qa[sz*sz],qb[sz*sz],qc[sz*sz];
typedef long long LL;
#define ri register int
ed *q1=qa,*q2=qb,*q3=qc;
char mmp[sz][sz];
int t,n,f1,f2,f3,t1,t2,t3;int X[]={1,-1,0,0},Y[]={0,0,1,-1};
bool vis1[sz][sz],vis2[sz][sz],f;
inline void init(){memset(vis1,0,sizeof vis1);memset(vis2,0,sizeof vis2);q1=qa,q2=qb,q3=qc;f1=f2=f3=t1=t2=t3=0;f=0;}
#define can(x,y) (x>0&&y>0&&x<=n&&y<=n)
inline void exbfs(){while(f1<t1&&f2<t2){if(t1-f1<t2-f2){t3=0;while(f1<t1){ed u=q1[f1++];for(ri i=0;i<4;++i){int x=u.x+X[i],y=u.y+Y[i];if(can(x,y)){if(vis2[x][y]){//正向找到终点or反向遍历到的点f=1;return;   }if(!vis1[x][y]&&mmp[x][y]!='#')vis1[x][y]=1,q3[t3++]=(ed){x,y};}}}swap(q1,q3);f1=0,t1=t3;}else{t3=0;while(f2<t2){ed u=q2[f2++];for(ri i=0;i<4;++i){int x=u.x+X[i],y=u.y+Y[i];if(can(x,y)){if(vis1[x][y]){f=1;return ;}if(!vis2[x][y]&&mmp[x][y]!='#')vis2[x][y]=1,q3[t3++]=(ed){x,y};}}}swap(q2,q3);f2=0,t2=t3;}}
}
int main(){scanf("%d",&t);while(t--)
{scanf("%d",&n);gets(mmp[0]);for(ri i=1;i<=n;++i) gets(mmp[i]+1);init();for(ri i=1;i<=n;++i)for(ri j=1;j<=n;++j)if(mmp[i][j]=='s')vis1[i][j]=1,q1[t1++]=(ed){i,j};else if(mmp[i][j]=='e')vis2[i][j]=1,q2[t2++]=(ed){i,j};exbfs();if(f) puts("YES");else puts("NO");
}

高精家族

高精N则运算

struct qwq{int a[100000];int len;
};
qwq operator + (qwq x,qwq y){int le=max(x.len,y.len);for(RI i=1;i<=le;++i){x.a[i]+=y.a[i];x.a[i+1]+=x.a[i]/10;x.a[i]%=10;}return x;
}
qwq operator - (qwq x,qwq y){int le=max(x.len,y.len);for(RI i=1;i<=le;++i){x.a[i]-=y.a[i];if(x.a[i]<0){x.a[i+1]-=1;x.a[i]+=10;}}return x;
}
qwq operator * (qwq x,qwq y){qwq c;for(RI i=1;i<=5000;++i)c.a[i]=0;for(RI i=1;i<=x.len;++i)for(RI j=1;j<=y.len;++j)c.a[i+j-1]+=x.a[i]*y.a[j];for(RI i=1;i<=5000;++i){c.a[i+1]+=c.a[i]/10;c.a[i]%=10;}return c;
}
qwq A,B,C;
void out(){int h=0;for(RI i=4950;i>=1;i--){int q=C.a[i];if(q!=0 && h==0)  h=1;if(h==1)         printf("%d",q);if(h==0&&i==1)     printf("%d",0);}
}
char s[1000000];
int main()
{scanf("%s",s);int lenx=strlen(s);for(RI i=0;i<lenx;++i)   A.a[lenx-i]=s[i]-'0';A.len=lenx;scanf("%s",s);lenx=strlen(s);for(RI i=0;i<lenx;++i)    B.a[lenx-i]=s[i]-'0';B.len=lenx;C=A*B;//C=A+B;C=A-B;out();
}

高精阶乘

int m=0;
read(n);a[1]=1;
for(RI i=1;i<=n;++i)
{for(RI j=1;j<=la;++j){a[j]*=i;a[j]+=m;m=a[j]/10;a[j]=a[j]%10;}while(m>0){la++;a[la]+=m%10;m/=10;}
}
for(RI i=la;i>=1;i--) write(a[i]);

高精阶乘の和

int a[100000],n,i,y,xy[100000],s[100000];//s[0]和a[0]表示两个数组的长度
//s表示答案,a表示阶乘,先算出阶乘,放在a里,再把s和它相加,更新s
void add(){//表示s=s+aint i;memset(xy,0,sizeof(xy));//xy为辅助数组,先将a+s放入xy,再将s更新为xyxy[0]=max(s[0],a[0]);//更长的为xy数组长度for (i=1;i<=xy[0];i++){xy[i]+=s[i]+a[i];//将每一位相加xy[i+1]=xy[i]/10;//进位xy[i]%=10;//进位}while (xy[xy[0]+1]>0) //进位{xy[xy[0]+2]=xy[xy[0]+1]/10;xy[xy[0]+1]%=10;xy[0]++;}s[0]=xy[0];//长度也要更新for (i=1;i<=xy[0];i++)s[i]=xy[i];//将xy给s
}
int main(){cin>>n;a[0]=1;    a[1]=1;//一定要是1,不然算阶乘为0s[0]=1;  s[1]=0;for (y=1;y<=n;y++){ //高精度乘法memset(xy,0,sizeof(xy));xy[0]=a[0];for (i=1;i<=a[0];i++){xy[i]+=a[i]*y;//阶乘xy[i+1]=xy[i]/10;//进位xy[i]%=10;}while (xy[xy[0]+1]>0)//进位 {xy[xy[0]+2]=xy[xy[0]+1]/10;xy[xy[0]+1]%=10;xy[0]++;}for (i=1;i<=xy[0];i++) a[i]=xy[i];//算出y!放入a内a[0]=xy[0];add();}for (i=s[0];i>=1;i--) cout<<s[i];

阶乘分解

void find_prime(int n){for(RI i = 2;i <= n;i ++){if(!he[i])           prime[++ tot] = i;for(RI j = 1;j <= tot && prime[j] * i <= n;j ++){he[prime[j] * i] = 1;if(i % prime[j] == 0)  break;}}
}
void ask_jc(int n){p = 0;int t = n;for(RI i = 1;i <= tot && prime[i] <= n;i ++){int c = prime[i];while(c <= n){cnt[i] += t / c;c *= c;p = i;}}
}
int main(){memset(he,0,sizeof(he));memset(prime,0,sizeof(prime));scanf("%d",&n);find_prime(n);ask_jc(n);for(RI i = 1;i <= p;i ++)if(cnt[i]){for(RI j = 1;j <= cnt[i];j ++)printf("%d ",prime[i]);}

归并排序+求逆序对

归并排序

int n,num[sz],tmp[sz];
void merge_sort(int l,int r){if(l==r) return;int mid=l+r>>1;merge_sort(l,mid),merge_sort(mid+1,r);int p=l,pl=l,pr=mid+1;while(pl<=mid||pr<=r){if(pr>r|| (pl<=mid&&num[pl]<=num[pr]) )tmp[p++]=num[pl++];elsetmp[p++]=num[pr++];}for(int i=l;i<=r;++i)num[i]=tmp[i];
}
int main(){cin>>n;for(int i=1;i<=n;++i) cin>>num[i];merge_sort(1,n);for(int i=1;i<=n;++i)  printf("%d ",num[i]);
}

是求逆序对的好方式

ll a[sz],tmp[sz];ll ans,n;
inline void merge(ll l,ll m,ll r)
{ll i=l;  ll j=m+1; ll k=l;while(i<=m&&j<=r){if(a[i]>a[j]){tmp[k++]=a[j++];ans+=m-i+1;}elsetmp[k++]=a[i++];}while(i <= m) tmp[k++]=a[i++];while(j <= r) tmp[k++]=a[j++];for(int i=l;i<=r;i++)a[i] = tmp[i];
}
inline void merge_sort(ll l,ll r){if(l<r){ll m=(l+r)>> 1;merge_sort(l,m);merge_sort(m+1,r);merge(l,m,r);}
}
int main(){read(n);for(ll i=0;i<n;i++) read(a[i]);merge_sort(0,n-1);cout<<ans;
}

手读手输(快读)

各种版本
这个随时随地用得上,对于100w以上输入的数据效果显著,多用于大数据输入输出
①读数字型

inline void read(int &x){x = 0;bool flag = 0;char ch = getchar();while(ch < '0' || ch > '9')    {if(ch == '-')   flag = 1;ch = getchar();}while(ch >= '0' && ch <= '9'){x = x * 10 + ch - '0';ch = getchar();}if(flag)        x *= -1;
}
inline void write(int x){if(x < 0)        putchar('-'),x *= -1;if(x / 10)        write(x / 10);putchar(x % 10 + '0');
}

②读串型

int read(string a){int x=0;if(a[0]=='-'){for(int i=1;i<a.length();i++)if(a[i]>='0'&&a[i]<='9')x = x*10+a[i]-'0';x=-x;}else{for(int i=0;i<a.length();i++)if(a[i]>='0'&&a[i]<='9')x = x*10+a[i]-'0';}return x;
}

更多优化卡时等等详情请见qwq不断更新的总结

=动态规划=

类型太多简单列列吧qwq,不太想乖乖整理了,把最近做的几个拿出来吧ε=(´ο`*))) 还有高精dp真是。。。↑_↓

背包

http://blog.csdn.net/lyhvoyage/article/details/8545852
(个人认为这个不知名大佬写的不错,再就是去看看背包九讲的前几讲emmmmm)

01
有N件物品和一个容量为V的背包。(每种物品均只有一件)第i件物品的费用是c[i],价值是w[i]。求解将哪些物品装入背包可使价值总和最大
eg:http://codevs.cn/problem/5709/
特征:明确的选择关系,给出体积限定,或物品数量为1

int a[sz],v,n,ans;
int w[sz],k[sz],dp[1010][1010];
int main()
{rd(v),rd(n);for(ri i=1;i<=n;++i)rd(w[i]),rd(k[i]);for(ri i=1;i<=n;++i)for(ri j=1;j<=v;j++)if(j>=w[i])dp[i][j]=max(dp[i-1][j],dp[i-1][j-w[i]]+k[i]);elsedp[i][j]=dp[i-1][j];cout<<dp[n][v];
}

这是二维转移,对于第一维我们可以优化掉,优化空间

int F[1001],c[1001],v[1001];
int main(){int s,n;cin>>s>>n;for(int k=1;k<=n;k++) cin>>c[k]>>v[k];for(int i=1;i<=n;i++)for(int j=s;j>=c[i];j--)//那个物体可以放进去 F[j]=max(F[j],F[j-c[i]]+v[i]);cout<<F[s];//询问能否将一个容量s的背包填到最大价值
}

完全
特征:物品数量无限,追求总和最大
有N种物品和一个容量为V的背包,每种物品都有无限件可用。第i种物品的费用是c[i],价值是w[i]。求解将哪些物品装入背包可使这些物品的费用总和不超过背包容量,且价值总和最大
同样有二维和一维写法

/*完全背包 每一个物品都有无限个
状态转移方程,d[i][j]=max(dp[i-1][j],dp[i-1][j-k*c[i]]+k*w[i]),if(j-k*c[i]>=0)
边界 dp[0][j]=0 j>=0&&j<=v尽量填充背包,不要求装满  dp[0][0]=0 dp[0][j]=-INF j>=1&&j<=v 恰好装满*/
const int V=1000,N=100;int dp[N][V],c[N],w[N],v,n;
int main()
{memset(dp,0,sizeof(dp));cin>>n>>v;for(int i=1;i<=n;i++) cin>>c[i]>>w[i];for(int i=1;i<=n;i++){for(int j=1;j<=v;j++)dp[i][j]=dp[i-1][j];for(int j=c[i];j<=v;j++)for(int k=1;k*c[i]<=j;k++)dp[i][j]=max(dp[i][j],dp[i-1][j-k*c[i]]+k*w[i]);}cout<<dp[n][v]<<" ";
}

一维写法:

int f[N],c[N],w[N],v,n;
int main(){cin>>v>>n;for(int i=1;i<=n;i++)cin>>c[i]>>w[i];for(int i=1;i<=n;++i)for(int j=c[i];j<=v;++j)f[j]=max(f[j],f[j-c[i]]+w[i]);cout<<f[v];
}

多重
特征:是每件物品给出确定的件数,求可得到的最大价值

多重背包问题要求简单,就是每件物品给出确定的件数,求可得到的最大价值
多重背包转换成 01 背包问题就是多了个初始化,把它的件数C 用二进制分解成若干个件数的集合,这里面数字可以组合成任意小于等于C的件数,而且不会重复,之所以叫二进制分解,是因为这样分解可以用数字的二进制形式来解释
比如:7的二进制 7 = 111 它可以分解成 001 010 100 这三个数可以组合成任意小于等于7 的数,而且每种组合都会得到不同的数拆分出来不全为1的数,比如13 = 1101 则分解为 0001 0010 0100 0110,前三个数字可以组合成 7以内任意一个数,即1、2、4可以组合为1——7内所有的数,加上 0110 = 6 可以组合成任意一个大于6 小于等于13的数,比如12,可以让前面贡献6且后面也贡献6就行了。虽然有重复但总是能把 13 以内所有的数都考虑到了,基于这种思想去把多件物品转换为,多种一件物品,就可用01 背包求解
二进制分解+01

int T,V,n,i,j,k,v[sz],w[sz],c[sz],dp[sz];
//v[]存价值,w[]存尺寸,c[]存件数 本题中价值是米重量,尺寸是米价格
int main()
{int sum,Value[sz],size[sz];
//sum存储分解完后的物品总数
//Value存储分解完后每件物品的价值
//size存储分解完后每件物品的大小
cin>>T;while(T--)
{sum=0;cin>>V>>n;for(i=0;i<n;i++){cin>>w[i]>>v[i]>>c[i];//对该种类的c[i]件物品进行二进制分解for(j=1;j<=c[i];j<<=1){//相当于x2Value[sum]=j*v[i];size[++sum]=j*w[i];c[i]-=j;}if(c[i]>0){Value[sum]=c[i]*v[i];size[++sum]=c[i]*w[i];}}//经过上面对每一种物品的分解,//现在Value[]存的就是分解后的物品价值//size[]存的就是分解后的物品尺寸//sum就相当于原来的n   下面就直接用01背包算法来解memset(dp,0,sizeof(dp));for(i=0;i<sum;i++)for(j=V;j>=size[i];j--)if(dp[j]<dp[j-size[i]]+Value[i])dp[j]=dp[j-size[i]]+Value[i];cout<<dp[V]<<endl;
}
return 0;
}

两种包一起

int n,m,dp[1010],t;int p[1010],h[1010],c[1010];
void wan(int v,int w){for(int i=v;i<=n;i++)if(dp[i]<dp[i-v]+w)  dp[i]=dp[i-v]+w;
}
void ling(int v,int w){for(ri i=n;i>=v;--i)if(dp[i]<dp[i-v]+w)dp[i]=dp[i-v]+w;
}
int main()
{rd(t);while(t--)
{memset(dp,0,sizeof(dp));rd(n),rd(m);for(ri i=1;i<=m;++i){rd(p[i]),rd(h[i]),rd(c[i]);if(p[i]*c[i]>=n)wan(p[i],h[i]);else{for(ri j=1;j<c[i];j<<1){ling(j*p[i],j*h[i]);c[i]=c[i]-j;}}}printf("%d\n",dp[n]);
} return 0;
}

混合
特征:限定不明确,包含三种背包的影子,求最大值
背包体积为V ,给出N个物品,每个物品占用体积为Vi,价值为Wi,每个物品要么至多取1件,要么至多取mi件(mi > 1) , 要么数量无限 , 在所装物品总体积不超过V的前提下所装物品的价值的和的最大值是多少?

有依赖背包
特征:明确的限定捆绑关系,体积or价值限定,求最大值

划分型

目前涉及到的划分型dp不多,算上数的划分这个题目的话也是寥寥几个,不知道总结的对不对,总之先把自己的想法写出来
eg:乘积最大 http://codevs.cn/problem/1017/
划分型dp和区间型dp区分上目前还未细致研究,但是听说挺相似的2333
对于划分dp应该是有明显的划分条件,将什么什么划分到哪里or在一个连续的阶段中插入分层处理。
个人觉得有时候这个分析很不好分析,对于这种问题我们要结合连续阶段分析划分的情况怎么处理,有时候我们会选择三层for循环来枚举断点,在断点处进行选择插入断点新情况和不选择插入的老情况的比较,进行答案的统计和更新

int a[sz][sz],f[sz][sz],n,m;
int main(){scanf("%d%d",&n,&m);for(int i=1;i<=n;i++)scanf("%c",&x[i]),a[i][i]=x[i]-'0';for(int i=1;i<=n;i++)for(int j=i+1;j<=n;j++)a[i][j]=a[i][j-1]*10+x[j]-'0';//i位->j位的数字for(int i=1;i<=n;i++)f[i][0]=a[1][i];//初始化for(int k=1;k<=m;k++)//循环分割次数for(int i=k+1;i<=n;i++)//分割k次至少需要k+1位数字for(int j=k;j<i;j++)//循环分割位置f[i][k]=max(f[i][k],f[j][k-1]*a[j+1][i]);//前面*后面的数字printf("%d\n",f[n][m]);
}

区间型

const int maxn = 110, INF = 100000000;
int n, a[maxn], sum[maxn], dp[maxn][maxn];
void solve()
{for (int i = 1; i <= n; i++)for (int j = i - 1; j >= 0; j--) {dp[j][i] = INF;for (int k = j; k < i; k++)dp[j][i] = min(dp[j][i], dp[j][k] + dp[k+1][i] + sum[i] - sum[j - 1]);}cout << dp[1][n] << endl;
}
int main() {cin >> n;for (int i = 1; i <= n; i++){cin >> a[i];sum[i] = sum[i - 1] + a[i];}solve();
}

状压型

http://www.lydsy.com/JudgeOnline/problem.php?id=1087

LL dp[10][100][521],ans;
LL tot,n,K,stay[101],cnt[101],pos;
//stay记录每种状态压缩后的值,cnt记录对应的状态中1的个数
bool mmp[101][101];
void dfs(LL k,LL put,LL pos)
//预处理,k是放了几颗,put是当前放的位置,now是当前状态压缩后的值
{stay[++tot]=pos;cnt[tot]=k;if(k>=(n+1)/2 || k>=K)return;for(RI i=put+2;i<=n;++i)dfs(k+1,i,pos+(1<<(i-1)));
}
void init()
{dfs(0,-1,0);//预处理出每种状态,共有tot种for(RI i=1;i<=tot;++i)for(RI j=1;j<=tot;++j)mmp[i][j]=mmp[j][i]=( (stay[i]&stay[j]) || ((stay[i]>>1)&stay[j]) || ((stay[i]<<1)&stay[j]))?0:1;//枚举某两种状态是否能相邻.一共有三种不能的情况:上下都是1,左上、右下是1,左下、右上是1 for(RI i=1;i<=tot;++i)dp[1][cnt[i]][i]=1ll;//边界
}
int main()
{freopen("FKing.in","r",stdin);freopen("FKing.out","w",stdout);read(n),read(K);init();for(RI i=2;i<=n;++i)for(RI j=0;j<=K;++j)for(RI pos=1;pos<=tot;++pos){if(cnt[pos]>j)continue;for(RI k=1;k<=tot;++k)if(mmp[k][pos]&&cnt[k]+cnt[pos]<=j)dp[i][j][pos]+=dp[i-1][j-cnt[pos]][k];//转移}for(RI i=1;i<=tot;++i)ans+=dp[n][K][i];

树型

eg:二维:没有上司的舞会
三维:愚蠢的矿工
树型DP的套路一般是处理树结构上的问题,当然区间和序列也可以转化成树来处理。树型DP出现指数级枚举组合数时,采用左儿子右兄弟法来处理

int fir[sz],nxt[sz],dp[sz][2];int f,t;int root,tot = 1,n,ru[sz];
bool use[sz];
void dfs(int p,int f){use[p] = 1;for(RI i = fir[p] ; i ; i = nxt[i]){int t = l[i].t;if(t != f && use[t]!=1){use[t] = 1;dfs(t,p);dp[p][0] = max(dp[p][0],dp[t][1]+dp[p][0]);dp[p][1] = max(dp[p][1],max(dp[t][1],dp[t][0])+dp[p][1]);}}
}
int main(){cin>>n;for(RI i = 1 ; i <= n ; i ++)scanf("%d",&dp[i][0]);for(RI i = 1 ; i < n ; i ++){scanf("%d%d",&f,&t);ru[f] ++;build(f,t),build(t,f);}scanf("%d%d",&root,&root);for(RI i = 1 ; i <= n ; i ++)if(ru[i] == 0){root = i;break;}dfs(root,-1);cout<<max(dp[root][0],dp[root][1])<<'\n';
}

棋盘型

eg:传纸条
前两个和后两个分别代表了两条不同的路径的状态,通过不同的转移(主要是那一长串max)来完成答案的统计

int m,n,x,f[60][60][60][60],a[55][55];
int main()
{cin>>m>>n;for(RI i=1;i<=m;++i)for(RI j=1;j<=n;++j){cin>>x; a[i][j]=x;}
for(RI i=1;i<=m;++i)for(RI j=1;j<=n;++j)for(RI k=1;k<=m;++k)for(RI l=1;l<=n;++l){f[i][j][k][l]=max( f[i-1][j][k-1][l], max(f[i][j-1][k-1][l],max(f[i-1][j][k][l-1],f[i][j-1][k][l-1]) ) )+a[i][j]+a[k][l];if(i==k&&j==l)f[i][j][k][l]-=a[i][j];
}printf("%d",f[m][n][m][n]);return 0;
}

还有像是乌龟棋这样的棋盘型的核心

f[0][0][0][0]=step[1];
for(int i=0;i<=s1;i++)for(int j=0;j<=s2;j++)for(int k=0;k<=s3;k++)for(int l=0;l<=s4;l++){now=i+j*2+k*3+l*4+1;if(i>0) f[i][j][k][l]=max(f[i][j][k][l],f[i-1][j][k][l]+step[now]);if(j>0) f[i][j][k][l]=max(f[i][j][k][l],f[i][j-1][k][l]+step[now]);if(k>0) f[i][j][k][l]=max(f[i][j][k][l],f[i][j][k-1][l]+step[now]);if(l>0) f[i][j][k][l]=max(f[i][j][k][l],f[i][j][k][l-1]+step[now]);
}
printf("%d\n",f[s1][s2][s3][s4]);

递推型

其实感觉这个更像是递推什么的emmmm
但是不加滚动数组的这个只能处理1w左右的数据,否则会TLE

eg:矿工配餐

五维DP只要不是很丧病,一般就是第一维枚举位置状态,第二三维表示第一个情况的选择状态,第四五维表示第二个情况的选择状态,最终用总的状态求解
多用于求相同的两者的符合题意状态之和的最大或最小值

eg:以使得两个煤矿的产煤量的总和最大

代码:

inline int check(int a,int b,int c){if(a==0&&b==0) return 1;if(a==0) return 1+(b!=c);//代表如果b!=c返回1 if(a==b&&b==c) return 1;if(a==b||b==c||a==c) return 2;return 3;
}
int t[sz],n,f[sz][4][4][4][4];
char s[sz];
int dp(int pos,int a,int b,int x,int y){if(pos==n+1) return 0;if(f[pos][a][b][x][y]!=-1)return f[pos][a][b][x][y];return f[pos][a][b][x][y]=max(dp(pos+1,b,t[pos],x,y)+check(a,b,t[pos]),dp(pos+1,a,b,y,t[pos])+check(x,y,t[pos]));
}
int main(){read(n);scanf("%s",s);for(ri i=0;i<n;++i)//!从0开始读 if( s[i] == 'B' ) t[i+1] = 1;else if( s[i] == 'M' ) t[i+1] = 2;else t[i + 1] = 3;memset(f,-1,sizeof(f));cout<<dp(1,0,0,0,0);return 0;
}

=数论=

快速幂

好东西,跑的飞快贼好的东西2333

LL sum,m,n;LL p=1e9+7;
LL pow(LL a,LL b)
{if(b==0) return 1;if(b==1) return a%p;LL t=(b>>1);LL x=pow(a,t);LL ans=( (x%p)*(x%p) )%p;if(b&1) ans=( (ans%p)*(a%p) )%p;return  ans%p;
}

反素数

eg:反素数
解题报告
反素数深度分析

LL ans,tot,n;
LL su[13]={1,2,3,5,7,11,13,17,19,23,29,31,37};
void dfs(LL num,LL shu,LL yue,LL f)
//num是第num个质数,shu是数值,yue是约数个数,f是次方所剩数
{if(tot<yue || (tot == yue && ans>shu) ){tot = yue;ans = shu;}LL j = 0,i = shu,div;while(j < f){j++;if(n/i < su[num])break;div=yue * (j+1);i=i*su[num];if(i <= n)dfs( num+1,i,div,j );}
}
int main(){read(n);dfs(1,1,1,30);cout<<ans;}

筛法

欧拉筛
使用广泛而且跑的贼快的筛法

int su[sz],n,m,cnt,x;bool pd[sz];
int main(){read(n);memset(pd,1,sizeof(pd));pd[0]=pd[1]=0;for(ri i=2;i<=n;++i){if(pd[i]){cnt++;su[cnt]=i;}for(ri j=1;j<=cnt;++j){if(i*su[j]>n)//在n范围内找完了所有素数 break;pd[i*su[j]]=0;//将确定的素数的整数倍的数全部排除if(i%su[j]==0)break; }}for(ri i=2;i<=n;++i)if(pd[i])printf("%d ",i);//输出质数
}

埃氏筛(埃拉托斯特尼筛法)
跑的比欧拉筛稍微慢一点

bool vis[sz];int n;
int main()
{cin>>n;vis[1]=1;for(int i=2;i<=sqrt(n);++i)if(!vis[i])for(int j=i*i;j<=n;j+=i)vis[j]=1;int ans=0;for(int i=2;i<=n;++i)if(vis[i]==0)ans++; //是0的就是质数 cout<<ans;//输出的是质数的个数
}

gcd系列

gcd&&lcm
最大公因数最小公倍数
倒是求最小公倍数的辗转相除法挺好玩2333

int gcd(int a,int b){if(b==0) return a;return gcd(b,a%b);}
int lcm(int a,int b){return a*b/gcd(a,b);}

exgcd
来自咸鱼的绝望眼神。exgcd是用来解不定方程的东西,通过这个我们可以求得一组不定方程的解,并由此求出其他解
eg:青蛙的约会
这可确实不是个。。。emmm怎么说的东西。。。再来份详解吧。。
http://blog.csdn.net/qq_36693514/article/details/78360583

LL exgcd(LL a,LL b,LL &x,LL &y){if(b==0){x=1;y=0;return a;}LL ans=exgcd(b,a%b,x,y);LL temp=x;x=y;y=temp-a/b*y;return ans;
}
LL cal(LL a,LL b,LL c){LL x,y;LL gcd=exgcd(a,b,x,y);if(c%gcd!=0) return -1;x*=c/gcd;//转化为a*x+b*y=c的解b/=gcd;//约去c后原来b就变为了b/gcd;if(b<0) b=-b;//如果b为负数就去绝对值//x=(x%b+b)%b;(求出的就是最小正整数解)LL ans=x%b;if(ans<=0) ans+=b;//求最小正整数解return ans;//返回的就是最小正整数解
}
int main(){  LL x,y,m,n,L;  while(scanf("%lld%lld%lld%lld%lld",&x,&y,&m,&n,&L)!=EOF)  {  LL ans=cal(m-n,L,y-x);  if(ans==-1) printf("Impossible\n");  else printf("%lld\n",ans);  }
}

费马小定理

主要是被用来求乘法逆元的
费马小定理:假如p是质数且a,p互质,那么 a^(p-1)≡1(mod p)
由此可得,a^(p-2) ≡ 1 / a (mod p),所以在mod p意义下,除以 a 等价于乘上 a^(p-2),即 a^(p-2) 为 a 的逆元

ll ksm(ll x,ll p){if(p == 0)        return 1;if(p == 1)        return x % mod;if(p == 2)        return ((x%mod) * (x%mod))%mod;int temp = ksm(x,p/2) % mod;if(p % 2 == 1)        return (((temp * temp) % mod) * (x%mod));if(p % 2 == 0)        return (temp * temp) % mod;
}
int get(int a){return ksm(a,mod-2);
}

CRT

int a[MAXN],b[MAXN];
LL exgcd(LL a,LL b,LL &x,LL &y)//扩展欧几里得
{if(b==0)  {x=1;y=0;return a;}else {LL p=exgcd(b,a%b,x,y);LL t=x;x=y;y=t-a/b*x;return p;}
}
/*x%a[i]==b[i]*/
LL China(int n)//中国剩余定理
{LL M=1,d,x=0,y;for(int i=1;i<=n;i++)M*=(LL)a[i];for(int i=1;i<=n;i++){LL w=M/(LL)a[i];exgcd(w,a[i],d,y);x=(x+d*w*b[i])%M;  }return (x+M)%M;
}
int main(){int n;scanf("%d",&n);for(int i=1;i<=n;i++)scanf("%d%d",&a[i],&b[i]);printf("%lld\n",China(n));
}

矩阵系列

矩阵乘法
矩阵乘法的规律:
第一个矩阵的第i行与第二个矩阵第j列对应相乘,再将这些数相加,得到一个行列数分别为第一矩阵行数,第二矩阵列数的新矩阵—>
矩阵C的行数等于矩阵A的行数,C的列数等于B的列数
eg:裸的矩阵乘法

LL jza[sz][sz],jzb[sz][sz],ans[sz][sz];
LL ai,aj,bi,bj;
int main()
{rd(ai),rd(aj);for(ri i=1;i<=ai;++i)for(ri j=1;j<=aj;++j)rd(jza[i][j]);rd(bi),rd(bj);for(ri i=1;i<=bi;++i)for(ri j=1;j<=bj;++j)rd(jzb[i][j]);for(ri i=1;i<=ai;++i)for(ri j=1;j<=bj;++j)for(ri k=1;k<=aj;++k)ans[i][j]+=jza[i][k]*jzb[k][j];for(ri i=1;i<=ai;++i){for(ri j=1;j<=bj;++j){printf("%lld ",ans[i][j]);}puts("");}return 0;
}

矩阵快速幂+斐波那契
矩阵快速幂:利用矩阵加速线性方程
eg:裸的矩阵快速幂

LL n,k;
struct matr{LL m[250][250];
}ans,base;
matr mult(matr a,matr b){matr tmp;for(ri i=1;i<=n;++i)for(ri j=1;j<=n;++j){tmp.m[i][j]=0;for(ri k=1;k<=n;++k)tmp.m[i][j]=(tmp.m[i][j]+a.m[i][k]*b.m[k][j])%mo;}return tmp;
}
void ksm(LL k){for(ri i=1;i<=n;++i)for(ri j=1;j<=n;++j)base.m[i][j]=ans.m[i][j];while(k){if(k%2==1)ans=mult(ans,base);base=mult(base,base);k/=2;}
}
int main(){rd(n),rd(k);for(ri i=1;i<=n;++i)for(ri j=1;j<=n;++j)rd(ans.m[i][j]);ksm(k-1);for(ri i=1;i<=n;++i){for(ri j=1;j<=n;++j)printf("%lld ",ans.m[i][j]);printf("\n");}
}

应用:求斐波那契
eg:裸的矩阵乘法求斐波那契
难点在初始矩阵的构造上,不好想,对于矩阵问题涉及的很少qwq

struct matr{LL m[2][2];
}ans,base;
LL n,k;
matr mult(matr a,matr b){matr tmp;for(ri i=0;i<2;++i)for(ri j=0;j<2;++j){tmp.m[i][j]=0;for(ri k=0;k<2;++k)tmp.m[i][j]=(tmp.m[i][j]+a.m[i][k]*b.m[k][j])%mod;}return tmp;
}
LL ksm(LL n){base.m[0][0]=1,base.m[0][1]=1,base.m[1][0]=1,base.m[1][1]=0;ans.m[0][0]=1,ans.m[0][1]=0,ans.m[1][0]=0,ans.m[1][1]=0;while(n){if(n%2==1)ans=mult(ans,base);base=mult(base,base);n/=2;}return ans.m[0][1];
}
int main(){while(scanf("%lld",&n))
{if(n==-1)break;printf("%lld\n",ksm(n));
}return 0;
}

组合数学

ε=(′ο`*)))唉
这东西明明数学上还没学到呢_(:з」∠)_,裂上杨辉三角就冲上来变成题了
eg:16のD2T1

LL t,n,m,k,ans;LL f[sz][sz],s[sz][sz];
int main(){read(t),read(k);for(RI i=0;i<=2333;++i){f[i][i]=1;f[i][0]=1;}for(RI i=1;i<=2333;++i)for(RI j=1;j<i;++j) f[i][j]=(f[i-1][j-1]%k+f[i-1][j]%k)%k;for(RI i=1;i<=2333;++i)for(int j=1;j<=i;++j){s[i][j]=s[i][j-1];if(f[i][j]==0)s[i][j]++;}
while(t--){read(n),read(m);ans=0;for(LL i=1;i<=n;++i) {LL j=min(i,m);ans+=s[i][j];}write(ans),puts("");
}return 0;
}

分解质因数

 rd(n);for(ri i=2;i<=n;i++)while(n!=i){if(n%i==0){printf("%lld*",i);n=n/i;}else break;}printf("%lld",n);

数学规律推理

首先得就是打表找规律,emmm各种打表啊什么的
大致就是Fibonacci,Catalan这样递推的
既是一个在dp中重要的推理又是在数论中重要的规律
很多数论的推理都是跟Fib挂钩,或者是Fib的变式
纯Fib的有骨牌覆盖问题
Fib类型变式的有昆虫繁殖啊什么的

=图论=

最短路(有权图)

Spfa
【模板】单源最短路

struct ed{int nxt,to,w;
}l[sz<<1];
int dis[sz<<1],fir[sz],tot;
int n,m,s;
bool use[sz];
inline void build(int f,int t,int w){l[++tot]=(ed){f,t,w};l[tot].nxt=fir[f];fir[f]=tot;
}
queue<int>q;
inline void spfa(){q.push(s);dis[s]=0;while(!q.empty()){int u=q.front();q.pop();use[u]=0;for(ri i=fir[u];i;i=l[i].nxt){int v=l[i].to;if(dis[v]>dis[u]+l[i].w){dis[v]=dis[u]+l[i].w;if(!use[v]){q.push(v);use[v]=1;}}}}
}

Spfa_slf
热浪
加了双端队列优化,避免被卡的尴尬(虽然也有专门卡slf的)注意头文件要加上< deque >

int n,m,s,e,fir[sz],nxt[sz<<1],dis[sz<<1],tot;
bool use[sz];
deque<int>q;
inline void spfa_slf(int s){memset(use,0,sizeof(use));memset(dis,0x3f,sizeof(dis));dis[s]=0;use[s]=1;q.push_front(s);while(!q.empty()){int u=q.front();q.pop_front();use[u]=0;for(ri i=fir[u];~i;i=nxt[i]){int v=l[i].t;if(dis[v]>dis[u]+l[i].d){dis[v]=dis[u]+l[i].d;if(q.empty() || dis[v]<dis[q.front()])q.push_front(v);elseq.push_back(v);use[v]=1;}}}
}

dij堆优化

const int SZ=101000;const int inf=214748364;
struct ss
{int u,dis;bool operator < (const ss &a) const{return dis>a.dis;}
};
int first[SZ<<1],nxt[SZ<<1],dis[SZ],tot=0;
bool vis[SZ];
priority_queue<ss>q;
int dij(int s,int t)
{dis[s]=0;q.push((ss){s,0});while(!q.empty()){ss now=q.top();q.pop();if(vis[now.u]) continue;vis[now.u]=1;for(int i=first[now.u];i;i=nxt[i]){int v=es[i].t;if(dis[v]>dis[now.u]+es[i].d){dis[v]=dis[now.u]+es[i].d;q.push((ss){v,dis[v]});}}}return dis[t];
}
int main(){int n,m,s,t;int u,v,w;scanf("%d%d%d%d",&n,&m,&s,&t);for(int i=1;i<=m;i++){scanf("%d%d%d",&u,&v,&w);build(u,v,w);build(v,u,w);}for(int i=1;i<=n;i++)  dis[i]=inf;printf("%d",dij(s,t));
}

floyd
多源最短路
用来求多源最短路,其中运用了dp的思想,但是时间复杂度高达n^3(不过写起来很快2333)

int dis[sz][sz],n,q;
int main()
{scanf("%d",&n);for(int i = 1;i <= n;i ++)for(int j = 1;j <= n;j ++)scanf("%d",&dis[i][j]);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]);scanf("%d",&q);while(q--){int a,b;scanf("%d%d",&a,&b);printf("%d\n",dis[a][b]);}
}

bellman_ford
其实感觉像spfa的劣化版,或者说spfa是队列优化的bellman,二者判断负环的方式不太一样,但都是通过松弛操作判断次数决定的

int n,m,s,e;int tot,dis[sz<<1];
inline void build(int f,int t,int d){l[++tot]=(ed){f,t,d};
}
void bellman()
{dis[s]=0;while(1){bool bh=0;for(ri i=1;i<=m*2;++i){ed e=l[i];if(dis[e.f]!=inf && dis[e.t]>dis[e.f]+e.d){dis[e.t]=dis[e.f]+e.d;bh=1;}}if(!bh)break;}
}
int main(){read(n),read(m),read(s),read(e);for(ri i=1;i<=n;++i) dis[i]=inf;for(ri i=1;i<=m;++i){int f,t,v;read(f),read(t),read(v);build(f,t,v);build(t,f,v);}bellman();cout<<dis[e];
}

最短路(无权图)

无权图:权值相等的图 bfs,dis=层数*权值;

二分图染色

建一次图,二分答案,对大于mid的边所连的两个点进行二分图染色

int n,m,ru,rv,rw,tot,s,ans;
int color[50010],first[500010],nxt[500010],w[100010];
bool flag;
int dfs(int k){for(int i=first[k];i!=-1;i=nxt[i])    {if(l[i].w<=s)//若当前找到的边的边权小于二分的最小值 continue;   //即当前边对答案无影响-----若两端点在同一集合(监狱)内,此边权 int x=l[i].v;//                        小于等于两集合内部最大值(此时二分的最小值) if(color[x]==color[k])//          -----若两端点位于不同集合,此边权 return 0;//                            不会产生影响力___可行性 if(color[x]==-1)//且若用当前边进行染色可能将原本理应分在一个集合内的两点分到不同集合 {               //导致后来的染色过程发生冲突使答案偏大color[x]=color[k]^1;//不能用来确定染色关系___必要性 if(!dfs(x))//这一部分不太理解的话可以先看下面 return 0;}}return 1;
}
int check(){for(int i=1;i<=n;i++){if(color[i]==-1&&first[i]!=-1){color[i]=1;if(!dfs(i))return 0;}}return 1;
}
int main(){memset(first,-1,sizeof(first));memset(color,-1,sizeof(color));scanf("%d%d",&n,&m);for(int i=1;i<=m;i++){scanf("%d%d%d",&ru,&rv,&rw);w[i]=rw;//记录怨气值=可能造成的冲突影响力 build(ru,rv,rw);build(rv,ru,rw);}sort(w+1,w+m+1);//从小到大排序-就可以二分啦...当然也可以从大到小. int l=1,r=m,mid;while(l+1<=r)//二分z市长看到的最小值-----对于同一集合内元素的怨气最大值,冲突影响力最大值 {mid=(l+r)>>1;//二分边的编号代表最小值,而不是直接二分边权  s=w[mid];    //可以让我们取得最准确的限定条件  memset(color,-1,sizeof(color));if(check())//染色判断是否可行 {ans=w[mid];//统计可行答案 r=mid;}else l=mid+1;}if(l==1&&r<l)//若无轮多小的冲突影响力都不会出现,即本年内监狱中未发生任何冲突事件 printf("0");//其实没有必要写..因为这种情况下ans不会被更新值为0.else printf("%d",ans);
}
/*为什么要用二分图染色?
题目要求分为两个集合,但对答案有影响的关系即存在于给定集合(也就是监狱)内部,也存在与集合之间
则可以自行限定另外的两个集合-----将对答案没有影响的关系(即边权小于等于二分最小值的边)
放于这两个集合内部,这些关系可以忽略,则其他对答案有影响的关系就位于集合之间,可以通过这些边染色
此时我们就得到了形如poor wyh题中的状况(二分图模型),
只不过这个状况不是直接确定的,而是由当前二分值确定的,
于是,进行二分图染色判断当前状况是否合理即能否进行这样的分配,最后二分出最小满足题目条件的解 */

第K短路

重难点在估价函数怎么写上,有的时候很不好想。在这里求第k短路,我们先从终点跑一遍到估价函数所到的点的最短路(这个最短路确定,是估价点不确定)
然后我们进行启发式最短路,跑一遍dij,

int n,m,S,E,k,h[sz];
bool use[sz],flag;
int fir[sz],nxt[sz<<1],tot,dis[sz<<1];
int fir1[sz],nxt1[sz<<1],tot1;
struct ed{int f,t,v;
}l[sz<<1],l1[sz<<1];
inline void build(int f,int t,int v){l[++tot]=(ed){f,t,v};nxt[tot]=fir[f];fir[f]=tot;
}
inline void build1(int f,int t,int v){l1[++tot1]=(ed){f,t,v};nxt1[tot1]=fir1[f];fir1[f]=tot1;
}
struct A
{int pos,g;//必须是pos在前g在后bool operator < (const A &a) const{return g + h[pos]>a.g+ h[a.pos];}
};
queue<int>q1;
void spfa(){memset(h,0x7fffffff,sizeof(h));q1.push(E);h[E]=0;while(!q1.empty()){int u=q1.front();use[u]=0;q1.pop();for(ri i=fir1[u];i;i=nxt1[i]){int v=l1[i].t;if(h[v] > h[u] + l1[i].v){h[v]=h[u]+l1[i].v;if(!use[v]){use[v]=1;q1.push(v);}}}}
}
priority_queue<A>q;
void Astar()
{q.push((A){S,0});int cnt=0;while(!q.empty()){A u=q.top();q.pop();if(u.pos==E){cnt++;if(cnt==k){flag=1;cout<<u.g;return ;}}for(ri i=fir[u.pos];i;i=nxt[i]){int v=l[i].t;q.push((A){v,u.g+l[i].v});}}
}
int main()
{rd(n),rd(m);for(ri i=1;i<=m;++i){int a,b,c;rd(a),rd(b),rd(c);build(a,b,c);build1(b,a,c);}rd(S),rd(E),rd(k);if(S==E) k++;spfa();Astar();if(flag==0)puts("-1");
}

差分约束

struct ed{LL t,d;
}l[sz<<1];
int fir[sz],nxt[sz<<1],vis[sz];
LL dis[sz];
int n,x,w,e,k,tot=1;
bool use[sz],fl;
inline void build(int f,int t,int d){l[++tot].t=t;l[tot].d=d;nxt[tot]=fir[f];fir[f]=tot;
}
deque<int>q;
void spfa(int s){q.push_back(s);use[s]=1;dis[s]=0;int u,v; while(!q.empty())  {u=q.front();q.pop_front();use[u]=0;for(ri i=fir[u];i;i=nxt[i]){v=l[i].t;if(dis[v]<dis[u]+l[i].d){dis[v]=dis[u]+l[i].d;vis[v]=vis[u]+1;if(vis[v]>n){//负环vis成use,TLE2次 fl=1;return ;}if(!use[v]){use[v]=1;if(q.empty())q.push_back(v);//没开双端TLE2次 elsev < q.front() ? q.push_front(v) : q.push_back(v);}}}}
}
int main()
{rd(n),rd(k);for(ri i=1;i<=k;++i){rd(x);rd(w),rd(e);switch(x){case(1):build(w,e,0);build(e,w,0);break;case(2):build(w,e,1);break;case(3):build(e,w,0);break;case(4):build(e,w,1);break;case(5):build(w,e,0);break;}}for(ri i=1;i<=n;++i)dis[i]=-inf;for(ri i=1;i<=n;++i){if(dis[i]==-inf){spfa(i);if(fl){puts("-1");return 0;}}}LL ans=0;//忘了定义为0,WA一次 for(ri i=1;i<=n;++i)ans+=dis[i];printf("%lld",ans+n);return 0;
}

并查集

普通版路径压缩并查集

void init(){for(int i=1;i<=n;i++) fa[i]=i;//初始化
}
void find(int x,int y){//查询 return fa[x]==x?x:fa[x]=find(fa[x]);//路径压缩
}
void merge(int x,int y){//合并 int f1=find(x);int f2=find(y);if(f1!=f2) fa[f1]=f2;
}

eg:https://www.luogu.org/problem/show?pid=2024
食物链 扩展域并查集

int fa[sz],ans;int n,k,d,x,y;
int find(int x){return x==fa[x]?x:x=find(fa[x]);}
int main(){rd(n),rd(k);for(ri i=1;i<=k*3;++i) fa[i]=i;for(ri i=1;i<=k;++i){rd(d),rd(x),rd(y);if(x>n||y>n){ans++;continue;}int x1=find(x),x2=find(x+n),x3=find(x+n*2);int y1=find(y),y2=find(y+n),y3=find(y+n*2);if(d==1){if(x1==y2||x2==y1) ans++;elsefa[x1]=y1,fa[x2]=y2,fa[x3]=y3;}if(d==2){if(x1==y1||x1==y2) ans++;elsefa[x1]=y3,fa[x2]=y1,fa[x3]=y2;}}we(ans);
}

最小生成树

Krusal
适用于稀疏图,而Prim适合稠密图 eg:繁忙的都市
http://www.lydsy.com/JudgeOnline/problem.php?id=1083

int fa[sz],n,m,ans;
struct ed{int f,t,v;
}l[sz<<1];
int find(int x){return x==fa[x]?x:x=find(fa[x]);}
void kru(){for(ri i=1;i<=n;++i){int x=find(l[i].f),y=find(l[i].t);if(x!=y){ans=l[i].v;fa[x]=y;}}
}
int main(){cin>>n>>m;for(ri i=1;i<=n;++i) fa[i]=i;for(ri i=1;i<=m;++i)cin>>l[i].f>>l[i].t>>l[i].v;kru();cout<<n-1<<' '<<ans;
}

拓扑排序

http://blog.csdn.net/qq_36693514/article/details/77816633主要关键是按照特定顺序,也就是出度入度来遍历,很有效的一种遍历方式,经常和dp放在一起考emmmm,比如bzoj上的食物链问题,就是一个很典型的拓扑(虽然没看出来dp)

http://blog.csdn.net/qq_36693514/article/details/78319010

queue<int>q;
int n,m,t,ru[sz],a[sz],b[sz],tot,cnt;
int fir[sz],nxt[sz],l[sz];
void top_sort()
{for(ri i=1;i<=n;++i)if(!ru[i]){q.push(i);
//          cout<<i; 求拓扑序列 }while(!q.empty()){int u=q.front();q.pop();cnt++; for(ri i=fir[u];i;i=nxt[i]){ru[l[i]]--;if(!ru[l[i]]){//              cout<<l[i];q.push(l[i]);}}}if(cnt>=n)cout<<"o(∩_∩)o";else {cout<<"T_T"<<'\n';cout<<n-cnt; }
}
int main(){cin>>n>>m;for(ri i=1;i<=m;++i){int f,t;cin>>f>>t;ru[t]++;build(f,t);}top_sort();
}

LCA

eg:小机房的树

int n,f,t,v;int m,x,y;LL rak[sz];
int fa[sz][21],dep[sz];int fir[sz],nxt[sz<<1],tot;
inline void btree(int x,int f,int v){dep[x]=dep[f]+1;fa[x][0]=f;rak[x]=v;for(ri i=1;i<=20;++i)fa[x][i]=fa[fa[x][x-1]][i-1];for(ri i=fir[x];~i;i=nxt[i])if(l[i].t!=f)btree(l[i].t,x,v+l[i].v);
}
int lca(int x,int y){if(dep[x]<dep[y]) swap(x,y);int c=dep[x]-dep[y];for(ri i=20;i>=0;--i){if(c & (1<<i))x=fa[x][i];}if(x==y) return x;for(ri i=20;i>=0;--i)if(fa[x][i]!=fa[y][i])x=fa[x][i],y=fa[y][i];return fa[x][0];
}
int main(){memset(fir,-1,sizeof(fir));cin>>n;for(ri i=1;i<n;++i){cin>>f>>t>>v;build(f,t,v),build(t,f,v);}btree(0,0,0);read(m);while(m --){read(x);read(y);printf("%d\n",rank[x] + rank[y] - (rank[lca(x,y)] << 1));}
}

tarjan

eg:爱在心中

int fir[sz],nxt[sz<<1],tot;
int ttot,dfn[sz],low[sz];
int stack[sz],size[sz],scc[sz];
bool in[sz];
int n,m,a,b,snum,cnt,du[sz];
struct ed{int f,t;
}l[sz<<1];
void tarjan(int u){dfn[u]=low[u]=++ttot;stack[++snum]=u;in[u]=1;for(ri i=fir[u];~i;i=nxt[i]){int v=l[i].t;if(!dfn[v]){tarjan(v);low[u]=min(low[u],low[v]);//low[v]!!,并非为dfn[v] }else if(in[v])low[u]=min(low[u],dfn[v]);}if(dfn[u]==low[u]){cnt++;while(stack[snum+1]!=u){scc[stack[snum]]=cnt;in[stack[snum]]=0;size[cnt]++;snum--;}}
}
int main()
{rd(n),rd(m);memset(fir,-1,sizeof(fir));for(ri i=1;i<=m;++i) {rd(a),rd(b);build(a,b);}for(ri i=1;i<=n;++i)if(!dfn[i])tarjan(i);for(ri i=1;i<=n;++i)for(ri j=fir[i];~j;j=nxt[j]){int v=l[j].t;if(scc[i]!=scc[v])du[scc[i]]++;}int sum1=0,sum2=0,x;for(ri i=1;i<=cnt;++i){if(size[i]>1)sum1++;if(!du[i]){sum2++;x=i;}}printf("%d\n",sum1);if(sum2==1&&size[x]!=1){for(ri i=1;i<=n;++i)if(scc[i]==x)printf("%d ",i);}else puts("-1");
}

=数据结构=

哈希

将符赋值成数,成为n进制下各种问题,在这种前提下对于符的问题解决更方便

char s[sz];
int mod,l,k,v[sz];
void hash(){v[l]=1;for(ri i=l-1;i>0;--i){v[i]=v[i+1]*26;v[i]%=mod;}k=0;for(ri i=1;i<=l;++i){k*=26;k+=s[i]-'A';k%=mod;}
}
inline int swwap(int i,int j){int sum=k;sum-=(v[i]*(s[i]-'A'))%mod;sum-=(v[j]*(s[j]-'A'))%mod;sum+=(v[i]*(s[j]-'A'))%mod;sum%=mod;sum+=(v[j]*(s[i]-'A'))%mod;sum%=mod;return sum;
}
inline void check(){if(k%mod==0){puts("0 0");return;}for(ri i=1;i<l;++i)for(ri j=i+1;j<=l;++j){if(swwap(i,j)%mod==0){printf("%d %d\n",i,j);return;}}puts("-1 -1");
}
int main()
{scanf("%s %d",s+1,&mod);l=strlen(s+1);hash();check();
}

线段树

#define L(x) (x << 1)//左儿子
#define R(x) (x << 1 | 1)//右儿子
#define sz(x) (tree[x].r - tree[x].l + 1)//区间大小
using namespace std;
const long long MAXN = 200000 + 5;
long long num[MAXN];
// l == 左;r == 右;p == now;
struct dot{    long long l,r;long long add,sum;//修改求和long long min,max;//最值标记bool xczhw;//没用打着玩……这是个梗QAQ
}tree[MAXN << 2];
//标记下放们 p == now
void update(long long p){tree[p].sum = tree[L(p)].sum + tree[R(p)].sum;tree[p].max = max(tree[L(p)].max,tree[R(p)].max);tree[p].min = min(tree[L(p)].min,tree[R(p)].min);
}
void spread(long long p){if(!tree[p].add)    return;tree[L(p)].max += tree[p].add;tree[R(p)].max += tree[p].add;tree[L(p)].min += tree[p].add;tree[R(p)].min += tree[p].add;tree[L(p)].add += tree[p].add;tree[R(p)].add += tree[p].add;tree[L(p)].sum += tree[p].add * sz(L(p));tree[R(p)].sum += tree[p].add * sz(R(p));tree[p].add = 0;//!!!!!!!update(p);
}//简单的建立
void build(long long l,long long r,long long p){tree[p].l = l,tree[p].r = r;if(l == r){tree[p].min = tree[p].max = tree[p].sum = num[l];return;}long long mid = (tree[p].l + tree[p].r) >> 1;build(l,mid,L(p));build(mid+1,r,R(p));update(p);
}
//区间修改
void change(long long l,long long r,long long p,long long v){if(l <= tree[p].l && tree[p].r <= r){tree[p].add += v;tree[p].min += v;tree[p].max += v;tree[p].sum += v*sz(p);return;}spread(p);long long mid = (tree[p].l + tree[p].r) >> 1;if(l <= mid) change(l,r,L(p),v);if(mid < r) change(l,r,R(p),v);update(p);
}
//区间求和
long long ask_sum(long long l,long long r,long long p){if(l <= tree[p].l && tree[p].r <= r)return tree[p].sum;spread(p);long long ans = 0,mid = (tree[p].l + tree[p].r) >> 1;if(l <= mid) ans += ask_sum(l,r,L(p));if(mid < r) ans += ask_sum(l,r,R(p));update(p);return ans;
}
//区间最大值
long long ask_max(long long l,long long r,long long p){if(l <= tree[p].l && tree[p].r <= r)return tree[p].max;spread(p);long long ans = 0,mid = (tree[p].l + tree[p].r) >> 1;if(l <= mid) ans = max(ans,ask_max(l,r,L(p)));if(mid < r) ans = max(ans,ask_max(l,r,R(p)));update(p);return ans;
}
//区间最小值
long long ask_min(long long l,long long r,long long p){if(l <= tree[p].l && tree[p].r <= r)return tree[p].min;spread(p);long long ans = 2333333,mid = (tree[p].l + tree[p].r) >> 1;if(l <= mid) ans = min(ans,ask_min(l,r,L(p)));if(mid < r) ans = min(ans,ask_min(l,r,R(p)));update(p);return ans;
}
long long n,m,a,b,c;string t;
int main()
{memset(num,0,sizeof(num));scanf("%lld",&n);for(long long i = 1; i <= n; i ++)       scanf("%lld",&num[i]);build(1,n,1);scanf("%lld",&m);for(long long i = 1; i <= m; i ++){cin >> t;if(t == "add"){scanf("%lld %lld %lld",&a,&b,&c);change(a,b,1,c);}else if(t == "sum")        {scanf("%lld %lld",&a,&b);printf("%lld\n",ask_sum(a,b,1));}else if(t == "max")        {scanf("%lld %lld",&a,&b);printf("%lld\n",ask_max(a,b,1));}else if(t == "min")        {scanf("%lld %lld",&a,&b);printf("%lld\n",ask_min(a,b,1));}}
}

扫描线算法

#define ls i<<1
#define rs i<<1|1
#define m(i) ((q[i].l+q[i].r)>>1)
typedef long long ll;
const int inf = 10000000 + 10;
const int sz = 111;
using namespace std;
double x[sz<<1];
struct edge{double l,r;double h;int f;
}e[sz<<1];
bool cmp(edge a,edge b){return a.h<b.h;}
struct node{int l,r;int s;double len;
}q[sz<<3];
void build(int i,int l,int r){q[i].l=l,q[i].r=r;q[i].s=0,q[i].len=0;if(l==r) return;int mid=m(i);build(ls,l,mid);build(rs,mid+1,r);
}
void up(int i){if(q[i].s) q[i].len=x[q[i].r+1]-x[q[i].l];else if(q[i].l==q[i].r) q[i].len=0;else q[i].len=q[ls].len+q[rs].len;
}
void update(int i,int l,int r,int xx){if(q[i].l==l&&q[i].r==r){q[i].s+=xx;up(i);return; }int mid=m(i);if(r<=mid) update(ls,l,r,xx);else if(l>mid) update(rs,l,r,xx);else{update(ls,l,mid,xx);update(rs,mid+1,r,xx);}up(i);
}
int n,kas;
int main(){while(scanf("%d",&n)==1&&n){int tot=0;for(int i=0;i<n;++i){double x1,y1,x2,y2;cin>>x1>>y1>>x2>>y2;edge &t1=e[tot];edge &t2=e[1+tot];t1.l=t2.l=x1,t1.r=t2.r=x2;t1.h=y1;t1.f=1;t2.h=y2;t2.f=-1;x[tot]=x1;x[tot+1]=x2;tot+=2;}sort(e,e+tot,cmp);sort(x,x+tot);int k=1;for(int i=1;i<tot;++i)if(x[i]!=x[i-1])x[k++]=x[i];build(1,0,k-1);double ans=0.0;for(int i=0;i<tot;++i){int l=lower_bound(x,x+k,e[i].l)-x;int r=lower_bound(x,x+k,e[i].r)-x-1;update(1,l,r,e[i].f);ans+=(e[i+1].h-e[i].h)*q[1].len;}cout<<"Test case #"<<++kas<<endl;printf("Total explored area: %.2f\n\n",ans);
}   return 0;
}

二维前缀和

eg:射命丸文
对于一次的查询答案ans应该等于s[x2][y2]-s[x2][y1-1]-s[x1-1][y2]+s[x1-1][y1-1],一个大的区域减去两个较小区域再加上被多减出去的那个区域,剩下的右下角小区块就是我们要求的区域

int num[sz][sz];int s[sz][sz];int n,m,r,c,ans;
int main()
{cin>>n>>m>>r>>c;for(int i=1;i<=n;++i)for(int j=1;j<=m;++j){cin>>num[i][j];s[i][j]=s[i-1][j]+s[i][j-1]+num[i][j]-s[i-1][j-1];}for(int i=1;i<=n;++i)for(int j=1;j<=m;++j)ans=max(ans,s[min(i+r-1,n)][min(j+c-1,m)]-s[min(i+r-1,n)][j-1]-s[i-1][min(j+c-1,m)]+s[i-1][j-1]);cout<<ans<<'\n';
}

栈/队列

栈的STL实现,,,好像还没掌握清楚w
先说说栈维护表达式运算吧w

这些都是emmmm
http://www.tyvj.cn/p/1041
http://www.tyvj.cn/p/1042
http://codevs.cn/problem/2178/

给出一个表达式,其中运算符仅包含+,-,*,/,^要求求出表达式的最终值数据可能会出现括号情况 还有可能出现多余括号情况
数据保证不会出现>maxlongint的数据。数据可能会出现负数情况

char ch[10005];LL num[10005], top1;LL opt[10005], top2;
void get_num(){if (!top2)  return;LL y = num[top1--], x = num[top1--];LL pos = opt[top2--];if (pos == 5) x = pow(x, y);if (pos == 4) x = x / y;if (pos == 3) x = x * y;if (pos == 2) x = x - y;if (pos == 1) x = x + y;num[++top1] = x;
}
int main(){scanf("%s", ch);LL n = strlen(ch);for (int i = 0; i < n;) {if (ch[i] >= '0' && ch[i] <= '9'){LL x = 0;while(ch[i] >= '0' && ch[i] <= '9'){x = x * 10 + ch[i] - '0'; i++;}num[++top1] = x;}if (ch[i] == '('){opt[++top2] = 0;i++;}if (ch[i] == '+') {while(top2 && opt[top2] != 0) get_num();opt[++top2] = 1; i++;}if (ch[i] == '-'){if (i == 0 || ch[i - 1] == '('){int x = 0; i++;while(ch[i] >= '0' && ch[i] <= '9'){x = x * 10 - (ch[i] - '0'); i++;}num[++top1] = x;}else{while(top2 && opt[top2] != 0)get_num();opt[++top2] = 2;i++;}}if (ch[i] == '*'){while(top2 && opt[top2] > 2)get_num();opt[++top2] = 3;i++;}if (ch[i] == '/'){while(top2 && opt[top2] > 2)get_num();opt[++top2] = 4;i++;}if (ch[i] == '^'){while(top2 && opt[top2] > 4)get_num();opt[++top2] = 5;i++;}if (ch[i] == ')'){while(top2 && opt[top2] != 0)get_num();top2--;i++;}}while(top2){if (opt[top2] == 0)top2--;else  get_num();}printf("%lld\n", num[top1]);
}

图的遍历(BFS版)

主要是找到一种既不重复又不遗漏的访问方法,可用来判断一个图是否连通,可用于穷举求解,可解决回溯问题.从图中某个顶点V0出发,并在访问此顶点后依次访问V0的所有未被访问过的邻接点,之后按这些顶点被访问的先后次序依次访问它们的邻接点,直至图中所有和V0有路径相通的顶点都被访问到;
若此时图中尚有顶点未被访问,则另选图中一个未曾被访问的顶点作起始点;
重复上述过程,直至图中所有顶点都被访问到为止
BFS所搜索到的都是最短的路径

void bfs(int k){int v[N]={0},i;     //N表示图的顶点个数 queue<int> q;v[k]=1;             //访问标记为1q.push(k);while(!q.empty()){k=q.front();q.pop();for(i=0;i<N;i++)if(a[k][i]==1&&!v[i]){       //a[k][i]表示顶点k,和i有关系q.push(i);v[i]=1;}}
}

树链剖分

这个。。。倒真是没太用过。。。相信着暴力出奇迹w(什么鬼)
树链剖分笔记详解

#define ls p<<1
#define rs p<<1|1
#define mid (shu[p].l+shu[p].r >>1)
#define RI register int
using namespace std;
const int sz = 300010;
int pos[sz],son[sz],top[sz],size[sz];int dep[sz],fa[sz],fir[sz],nxt[sz];
int w[sz],tot,n,q,cnt,x,y,num;
char ch[15];
struct node{int l,r;int sum,max;
}shu[sz<<2];
struct ed{int f,t;
}l[sz<<1];
inline void add(int f,int t){l[++tot]=(ed){f,t};nxt[tot]=fir[f];fir[f]=tot;
}
inline void build(int p,int l,int r){shu[p].l=l,shu[p].r=r;if(l==r){shu[p].sum = shu[p].max=0;return;}int midd = l+r>>1;build(ls,l,midd);build(rs,midd+1,r);shu[p].sum=shu[ls].sum+shu[rs].sum;shu[p].max=max(shu[ls].max,shu[rs].max);
}
void dfs1(int k,int f,int d)
{dep[k]=d;fa[k]=f;size[k]=1;for(RI i=fir[k];i;i=nxt[i]){int x=l[i].t;if(x==f)   continue;dfs1(x,k,d+1);size[k]+=size[x];if(!son[k]||size[x]>size[son[k]])son[k]=x;}
}
void dfs2(int k,int tot){top[k]=tot;pos[k]=++num;if(!son[k])  return;dfs2(son[k],tot);for(RI i=fir[k];i;i=nxt[i]){int x=l[i].t;if(x!=son[k]&&x!=fa[k])dfs2(x,x); }
}
void in(int p,int x,int v){if(shu[p].l==shu[p].r){shu[p].sum=shu[p].max=v;return;}if(x<=mid) in(ls,x,v);else if(x>mid)  in(rs,x,v);shu[p].sum=shu[ls].sum+shu[rs].sum;shu[p].max=max(shu[ls].max,shu[rs].max);
}
int qsum(int p,int l,int r)
{if(shu[p].l>=l&&shu[p].r<=r)return shu[p].sum;int ans=0;if(l<=mid)  ans+=qsum(ls,l,r);if(r>mid)   ans+=qsum(rs,l,r);return ans;
}
int qmax(int p,int l,int r)
{if(shu[p].l>=l&&shu[p].r<=r)return shu[p].max;int ans=-10000007;if(l<=mid)  ans=max(ans,qmax(ls,l,r));if(r>mid)  ans=max(ans,qmax(rs,l,r));return ans;
}
int dosum(int x,int y)
{int ans=0;while(top[x]!=top[y]){if(dep[top[x]]<dep[top[y]])swap(x,y);ans+=qsum(1,pos[top[x]],pos[x]);x=fa[top[x]];} if(pos[x]>pos[y])   swap(x,y);ans+=qsum(1,pos[x],pos[y]);return ans;
}
int domax(int x,int y)
{int ans=-1e8;while(top[x]!=top[y]){if(dep[top[x]]<dep[top[y]])swap(x,y);ans=max(ans,qmax(1,pos[top[x]],pos[x]));x=fa[top[x]];}if(pos[x]>pos[y])swap(x,y);ans=max(ans,qmax(1,pos[x],pos[y]));return ans;
}
int main()
{read(n);for(RI i=1;i<n;i++){read(x),read(y);add(x,y),add(y,x);}for(RI i=1;i<=n;i++) read(w[i]);dfs1(1,0,1);dfs2(1,1);build(1,1,n);for(RI i = 1;i <= n;i ++)in(1,pos[i],w[i]);read(q);while(q--){scanf("%s",ch);read(x),read(y);if(ch[0]=='C'){w[x]=y;in(1,pos[x],y);}else{if(ch[1]=='M')printf("%d\n",domax(x,y));elseprintf("%d\n",dosum(x,y));}}
}

字符串

Kmp

int len1,len2,tot;int Next[100010],pos[100010];char s[1000010],t[100010];
void initNext(){int j=0;for(int i=2;i<=len2;i++){while(j&&t[i]!=t[j+1])j=Next[j];if(t[i]==t[j+1])j++;Next[i]=j;}
}
/*void initNext(){//从0开始存 int j=-1;Next[0]=-1;for(int i=1;i<len;i++){while(j!=-1&&t[i]!=t[j+1])j=Next[j];if(t[i]==t[j+1])j++;Next[i]=j;}
}*/
int KMP(){int j=0,ans=0;for(int i=1;i<=len1;i++){while(j&&s[i]!=t[j+1])j=Next[j];if(s[i]==t[j+1])j++;if(j==len2){//ans++;pos[++tot]=i;j=Next[j];}}//return ans;
}
int main(){scanf("%s%s",s+1,t+1);len1=strlen(s+1);len2=strlen(t+1);initNext();KMP();for(int i=1;i<=tot;i++)printf("%d\n",pos[i]-len2+1);for(int i=1;i<=len2;i++)printf("%d ",Next[i]);
}

其他算法

随机化

const int SIZE=10010;const int INF=233333333;
int num[SIZE];int sum1=0,sum2=INF,n;
void randnum(){//随机化for(int i=1;i<=n;i++){int x=rand()%n+1;while(x==i) x=rand()%n+1;swap(num[i],num[x]);}
}
void getans(){//贪心int ans1=num[1],ans2=0,t1=1,t2=0;for(int i=2;i<=n;i++) {if(t1==t2-1)ans1+=num[i],t1++;else ans2+=num[i],t2++;}if(ans1>ans2) swap(ans1,ans2);if(abs(ans1-ans2)<abs(sum1-sum2))sum1=ans1,sum2=ans2;
}
int main()
{srand(time(0));scanf("%d",&n);for(int i=1;i<=n;i++)scanf("%d",&num[i]);for(int i=1;i<=100000;i++){getans();randnum();}printf("%d %d",sum1,sum2);
}

STL大法

sort+unique
eg:明明的随机数unique返回值是指针,指向去重后序列最后一项的后一项,要输出值的话需要减去位置下标
重复的元素会被放到后面,只能去掉连续的重复元素,要先排序

int main(){cin>>n;for(int i=1;i<=n;++i) cin>>a[i];
sort(a+1,a+n+1);int m=unique(a+1,a+n+1)-a-1;cout<<m<<endl;for(int i=1;i<=m;++i)  cout<<a[i]<<' ';
}

NOIP常考模板粗略集合包相关推荐

  1. 为什么你学不会递归?告别递归,谈谈我的一些经验 关于集合中一些常考的知识点总结 .net辗转java系列(一)视野 彻底理解cookie,session,token...

    为什么你学不会递归?告别递归,谈谈我的一些经验 可能很多人在大一的时候,就已经接触了递归了,不过,我敢保证很多人初学者刚开始接触递归的时候,是一脸懵逼的,我当初也是,给我的感觉就是,递归太神奇了! 可 ...

  2. 前端笔试常考设计模式,操作系统,数据结构,ACM模板,经典算法,正则表达式,常用方法

    考试时允许使用草稿纸,请提前准备纸笔.考试过程中允许上厕所等短暂离开,但请控制离开时间 笔试得分60%一般通过,面试答对80%才能通过 合集:2023年最全前端面试题考点HTML5+CSS3+JS+V ...

  3. 【附答案】Java面试2019常考题目汇总(一)

    转载自  [附答案]Java面试2019常考题目汇总(一) 一.JAVA基础篇-概念 1.简述你所知道的Linux: Linux起源于1991年,1995年流行起来的免费操作系统,目前, Linux是 ...

  4. JAVA面试常考系列三

    转载自 JAVA面试常考系列三 题目一 什么是迭代器(Iterator)? 迭代器(iterator)是一种对象,它能够用来遍历标准模板库容器中的部分或全部元素,每个迭代器对象代表容器中确定的地址.迭 ...

  5. 阿里前端常考vue面试题汇总

    Vuex中actions和mutations有什么区别 题目分析 mutations和actions是vuex带来的两个独特的概念.新手程序员容易混淆,所以面试官喜欢问. 我们只需记住修改状态只能是m ...

  6. 每日一练 | 20道常考Python面试题大总结

    每日一练 如果要对数据分析面试题进行归纳总结,基本可以分为三大类,分别是技术题.逻辑思维题.业务场景题. 本栏目旨在为小伙伴们分享常考/经典的数据分析面试题,大家在学习之余也可以进行自测,巩固学习成果 ...

  7. 2020Android面试心得:斩获3个大厂offer后,大厂常考知识点 面试技巧出炉

    复习计划的制定和进度的把控也很重要,可以参考别人的学习计划去学习,再根据自己的实际情况去做适当的调整. 复习技巧 我一直认为学习没有捷径可言.我信奉"好记性不如烂笔头",也信奉&q ...

  8. 由浅入深 65个JS常考面试题

    由浅入深逐个击破 JS常考面试题(上篇) 1. 介绍一下JS的基本数据类型,值是如何存储的? JavaScript一共有8种数据类型,其中有7种基本数据类型:Undefined.Null.Boolea ...

  9. 20道常考Python面试题大总结

    一般来说,面试官会根据求职者在简历中填写的技术及相关细节来出面试题.一位拿了大厂技术岗Special Offer的网友分享了他总结的面试经验.当时,面试官根据他在简历中所写的技术,面试题出的范围大致如 ...

  10. 分解例题及解析_【高考物理】考前梳理,高中物理经典常考例题(带解析),收藏起来考试不低于90+!...

    物理应该是理综里最让同学们头疼的一科.最后的压轴大题更是让很多人不知道该怎么下手,题型复杂难理解,简直是丢分"小能手". 别怕!学姐来拯救你们了!高中物理经典常考例题(带解析),考 ...

最新文章

  1. MySQL 学习笔记(2)— 通配符/正则表达/运算符
  2. storm_常用命令
  3. 【Android 系统开发】 Android 系统启动流程简介
  4. gitlable iphone_使用gitlab ci构建IOS包并发送通知消息到企业微信
  5. 【定时器/中断/PWM】利用一个定时器实现一路PWM波的输出---点亮LED
  6. php authorization,PHP CURL设置Authorization
  7. html前端开发作品,Web前端开发(HTML5+CSS3)
  8. 肖哥所有课程/HCNA HCNP/安全/云计算/虚拟化/linux/视频教程/资料软件下载链接
  9. python共享单车数据分析_利用python分析共享单车项目
  10. 解决visio中插入符号出现乱码
  11. 【大数据】Linkis前端管理台如何部署
  12. MySQL从入门到入魔,总结我的学习历程,给有需要的人看!
  13. java开发工程师面试自我介绍_Java程序员面试如何自我介绍HR这一关
  14. 年终盘点!2022顶会论文代码大合集!
  15. error C1010: 在查找预编译头时遇到意外的文件结尾。是否忘记了向源中添加“#include “pch.h“
  16. json c语言开发,JSON c语言开发指南
  17. 《F4+2团队项目需求改进与系统设计》
  18. 数睿数据受邀参与中俄数字经济高峰论坛,并发布企业级无代码新场景
  19. 报道|香港科大商学院【在商言商·思享会】(第一场)“企业如何抓住新一代科技红利”...
  20. 小学计算机课标教学大纲的依据,中小学教学大纲为何改成课程标准?

热门文章

  1. android实现支付功能,Android支付宝支付开发实例
  2. 一、java入门(高琪java300集+java从入门到精通笔记)
  3. QQ号被盗了申诉回来马上又被盗了怎么办
  4. 看刘未鹏先生的博客的一些摘记
  5. 基于 Retina-GAN 的视网膜图像血管分割
  6. C语言程序设计第六次作业
  7. html tbody增加行,实现所有行变色,所有行删除。给出的结构中少了tbody,加上就可以了。...
  8. dub解析json为构
  9. WIFI类物联网产品配网方式简述
  10. 彪悍的人生不需要解释,需要解释的人生是软弱的