oi各类模板集
https://www.luogu.org/paste/h3mzcfo1
https://www.cnblogs.com/phemiku/p/11622062.html
1.快速幂与快速乘
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int kase, a, b, q;
ll c, d, r;
int qpow(int a, int b, int q) {
ll s = 1;
while (b) {
if (b & 1)
s = s * a % q;
a = (ll)a * a % q;
b >>= 1;
}
return s;
}
ll qmul(ll c, ll d, ll r) {
ll s = 0;
while (d) {
if (d & 1)
s = (s + c) % r;
c = (c + c) % r;
d >>= 1;
}
return s;
}
int main() {
scanf("%d", &kase);
while (kase--) {
scanf("%d%d%d%lld%lld%lld", &a, &b, &q, &c, &d, &r);
printf("%d %lld
", qpow(a, b, q), qmul(c, d, r));
}
}
2.归并排序
//划分问题:把序列分成元素个数尽量相等的两半
//递归求解:把两半元素分别排序
//合并问题:把两个有序表合并为一个
//如果左边最小的数都比右边这个数大,
//那么左边剩余的所有数都会比右边这个数大
#include <bits/stdc++.h>
using namespace std;
#define N 1000005
int n, a[N], b[N];
long long cnt;
void merge_sort(int l, int r) {
if (l < r) {
int mid = (l + r) / 2;
int i = l;
int p = l, q = mid + 1;
merge_sort(l, mid);
merge_sort(mid + 1, r);
while (p <= mid || q <= r)
if (q > r || (p <= mid && a[p] <= a[q]))
b[i++] = a[p++];
else {
b[i++] = a[q++];
cnt += mid - p + 1; //将逆序对的个数累加起来
}
for (i = l; i <= r; i++) a[i] = b[i];
}
}
int main() {
scanf("%d", &n);
for (int i = 1; i <= n; i++) scanf("%d", &a[i]);
merge_sort(1, n);
printf("%lld", cnt);
}
3.ST表
#include <bits/stdc++.h>
using namespace std;
const int N = 500009;
int m, Log[N];
struct ST {
int st[21][N], n;
int query(int l, int r) {
assert(l <= r && r <= n);
int t = Log[r - l + 1];
return min(st[t][l], st[t][r - (1 << t) + 1]);
}
void push_back(int x) {
st[0][++n] = x;
for (int i = 1;; i++) {
int l = n - (1 << i) + 1;
if (l >= 1) {
st[i][l] = min(st[i - 1][l], st[i - 1][l + (1 << (i - 1))]);
} else
break;
}
}
void pop_back() { n--; }
} st;
int main() {
scanf("%d", &m);
for (int i = 2; i < N; i++) {
Log[i] = Log[i >> 1] + 1;
}
while (m--) {
char opt[9];
scanf("%s", opt);
if (opt[0] == 'I') {
int x;
scanf("%d", &x);
st.push_back(x);
} else if (opt[0] == 'Q') {
int l, r;
scanf("%d%d", &l, &r);
printf("%d
", st.query(l, r));
} else {
st.pop_back();
}
}
return 0;
}
4.左偏树
// ①:空节点为-1(性质推得)
// ②:删除操作:将其左右子树合并,接上去即可
// 插入操作:将插入的点用倍增合成一树,插入即可
// 替换操作:先删除再插入(注意删除时d[x]=r[x]=v[x]=l[x]=0)
#include<bits/stdc++.h>
#define Int register int
#define N 100005
using namespace std;
int n,m;
int fa[N],son[N][2],dead[N],dist[N],val[N];
int read (int &x){
x = 0;
char c = getchar();
int f = 1;
while(c < '0' || c > '9') {if (c == '-') f = -f;c = getchar();}
while(c >= '0' && c <= '9') {x = (x << 3) + (x << 1) + c - '0';c = getchar();}
return x*f;
}
void write (int x){
if(x < 0) {x = -x;putchar ('-');}
if(x > 9) write (x / 10);
putchar (x % 10 + '0');
}
int findSet (int x){
if (x != fa[x])
fa[x] = findSet (fa[x]);
return fa[x];
}
int Merge (int x,int y){
if (!x || !y)
return x | y;
//if(x==0) return y; //只剩某一子数(点)的情况
//if(y==0) return x;
//判断到尽头,儿子为空要返回对应的另一结点
if (val[x] > val[y] )
swap (x,y);
//如果值x大于y 或者值相同情况下 x的位置在y右边 交换
son[x][1] = Merge (son[x][1],y);
//将y不断地和x的右儿子进行合并
//将合并后的新的右儿子的父亲边连上
dist[x] = dist[son[x][1]] + 1;
//fa[lson[x]]=fa[rson[x]]=fa[x]=x;
//如果右儿子的dis要大于左儿子 进行交换
//dis[x]=(rson[x]==0?0:dis[rson[x]]+1);
//x的dis为其右儿子的dis+1
//若无右儿子则dis为0
if (dist[x] > dist[son[x][0]] + 1)
swap (son[x][0],son[x][1]);
fa[son[x][0]] = fa[son[x][1]] = fa[x] = x;
return x;
}
int Ask (int x){
dead[x] = 1;
int tmp = val[x];
fa[son[x][0]] = son[x][0];
fa[son[x][1]] = son[x][1];
fa[x] = Merge (son[x][0],son[x][1]);
return tmp;
}
signed main(){
read(n),read(m);
for (Int i = 1;i <= n;++ i)
fa[i] = i,read (val[i]);
for (Int i = 1;i <= m;++ i) {
int opt;
read (opt);
if(opt == 1){
int x,y;
read (x),read (y);
if (dead[x] || dead[y]) continue;
x = findSet (x),y = findSet (y);
if (x != y)
fa[x] = fa[y] = Merge (x,y);
} else if(opt == 2){
int x;
read (x);
if(dead[x]) puts ("-1");
else write (Ask (findSet (x))),putchar ('
');
}
}
}
5.最短路
(1)SPFA
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 9;
int n, m, mod;
struct Edge {
int v, w;
Edge *nxt;
bool ok;
} e[N<<1];
int e_cnt;
Edge *head[N];
void addEdge(int u, int v, int w) {
e[++e_cnt] =(Edge){ v, w, head[u], false };
head[u] = &e[e_cnt];
}
int dis[N];
bool inq[N];
queue<int> q;
void SPFA() {
q.push(1);
dis[1] = 0;
inq[1] = true;
while (!q.empty()) {
int u = q.front();
q.pop();
for (Edge *i = head[u]; i != NULL; i = i->nxt) {
int v = i->v, w = i->w;
if (dis[v] > dis[u] + w ) {
dis[v] = dis[u] + w;
if (!inq[v]) {
q.push(v);
inq[v] = true;
}
}
}
inq[u] = false;
}
}
int ind[N], f[N];
void dp() {
f[1] = 1;
q.push(1);
inq[1] = true;
while (!q.empty()) {
int u = q.front();
q.pop();
for (Edge *i = head[u]; i != NULL; i = i->nxt) {
int v = i->v, w = i->w;
if (dis[v] == dis[u] + w) {
i->ok = true;
++ind[v];
if (!inq[v]) {
q.push(v);
inq[v] = true;
}
}
}
}
q.push(1);
while (!q.empty()) {
int u = q.front();
q.pop();
for (Edge *i = head[u]; i != NULL; i = i->nxt) {
if (!(i->ok)) continue;
int v = i->v, w = i->w;
f[v] = (f[v] + f[u]) % mod;
if (--ind[v] == 0)
q.push(v);
}
}
}
int main() {
int kase;
scanf("%d", &kase);
while (kase--) {
scanf("%d%d%d", &n, &m, &mod);
e_cnt = 0;
for (int i = 1; i <= n; ++i) {
head[i] = NULL;
dis[i] = 1e9;
f[i] = 0;
ind[i] = 0;
inq[i] = false;
}
for (int i = 0, x, y, z; i < m; ++i) {
scanf("%d%d%d", &x, &y, &z);
addEdge(x, y, z);
}
SPFA();
dp();
for (int i = 2; i <= n; ++i)
printf("%d ", f[i]);
puts("");
}
}
(2)Dijkstra
#include<bits/stdc++.h>
using namespace std;
const int N=1e7+10;
int n,m,head[N],tot;
int dis[N],t,rxa,rxc,rya,ryc,rp;
struct node{
int to,nxt,w;
}e[N];
bool inq[N];
priority_queue<pair<int ,int > >q;
int read(){
int x=0,f=1;
char ch=getchar();
while(ch>'9'||ch<'0'){
if(ch=='-') f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9'){
x=(x*10+ch-'0');
ch=getchar();
}
return x*f;
}
void add(int u,int v,int w){
e[++tot].to=v;
e[tot].w=w;
e[tot].nxt=head[u];
head[u]=tot;
}
int main(){
n=read(),m=read(),t=read();
rxa=read(),rxc=read(),rya=read(),ryc=read();
rp=read();
int x=rxc%rp,y=ryc%rp;
int a = min(x%n+1,y%n+1) , b=y%n+1;
add(a,b,1e8-100*a);
for(int i=1;i<=m-t;i++){
int xx,yy,zz;
xx=read(),yy=read(),zz=read();
add(xx,yy,zz);
}
memset(dis,0x3f,sizeof dis);
dis[1]=0;
q.push(make_pair(0,1));
inq[1]=0;
while(!q.empty()){
int x=q.top().second;
q.pop();
if(inq[x]) continue;
inq[x]=1;
for(int i=head[x];i;i=e[i].nxt){
int to=e[i].to,w=e[i].w;
if(dis[to]>dis[x]+w){
dis[to]=dis[x]+w;
q.push(make_pair(-dis[to],to));
}
}
}
printf("%d",dis[n]);
}
(3) BFS
最短路计数(求1到其他顶点的最短路条数)
( 边权为1时 )
#include<bits/stdc++.h>
using namespace std;
const int N=1e6+5,M=4e6+5;
int mod=1e5+3;
int n,m,x,y,tot;
int head[N],to[N],nxt[M],d[N],ans[N];
bool p[N];
queue<int>q;
void add(int x,int y){
to[++tot]=y;
nxt[tot]=head[x];
head[x]=tot;
}
int main(){
scanf("%d%d",&n,&m);
while(m){
scanf("%d%d",&x,&y);
add(x,y);
add(y,x);
m--;
}
for(int i=1;i<=n;i++){
d[i]=1e9;
p[i]=0;
}
d[1]=0;
p[1]=1;
ans[1]=1;
q.push(1);
while(q.size()){
x=q.front();
q.pop();
p[x]=0;
for(int i=head[x];i;i=nxt[i]){
y=to[i];
if(d[y]>d[x]+1){
d[y]=d[x]+1;
ans[y]=ans[x];
if(!p[y]){
q.push(y);
p[y]=1;
}
}
else if(d[y]==d[x]+1){
ans[y]+=ans[x];
ans[y]%=mod;
}
}
}
for(int i=1;i<=n;i++)
printf("%d
",ans[i]);
}
6.MST(最小生成树)
(1)洛谷模板题
#include <bits/stdc++.h>
using namespace std;
const int N = 400015;
struct edge {
int u,v,w;
} edges[N];
int n, m, cnt, tot,fa[N];
long long ans;
bool cmp(edge x, edge y) { return x.w < y.w; }
int find(int x) {
if(x == fa[x]) return x;
else return fa[x] = find(fa[x]);
}
bool merge(int x, int y) {
x = find(x);
y = find(y);
if (x == y) return 0;
fa[x] = y;
return 1;//??
}
int main() {
scanf("%d%d", &n, &m);
for (int i = 1; i <= m; i++) {
int x, y, p;
scanf("%d%d%d", &x, &y, &p);
edges[++tot] = (edge){ x, y, p };
}
sort(edges + 1, edges + 1 + tot, cmp);
for (int i = 1; i <= n; i++) fa[i] = i;
for (int i = 1; i <= tot; i++) {
int u = edges[i].u;
int v = edges[i].v;
if (merge(u, v)) {
ans += edges[i].w;
cnt++;
}
if (cnt == n - 1) break;
}
if (cnt != n - 1) printf("orz"); //什么鬼输出
else printf("%lld", ans);
}
(2)
#include <bits/stdc++.h>
using namespace std;
const int N = 200010;
struct Edge {
int to, w;
};
vector<Edge> G[N];
int n, m, done[N];
struct Node {
int d, v;
bool operator<(const Node &rhs) const { return d > rhs.d; }
};
priority_queue<Node> q;
int main() {
scanf("%d%d", &n, &m);
for (int i = 0; i < m; i++) {
int u, v, w;
scanf("%d%d%d", &u, &v, &w);
G[u].push_back((Edge){ v, w });
G[v].push_back((Edge){ u, w });
}
q.push((Node){ 0, 1 });
long long ans = 0;
for (int i = 1; i <= n; i++) {
Node u;
do {
if (!q.size()) {
puts("-1");
return 0;
}
u = q.top();
q.pop();
} while (done[u.v]);
ans += u.d;
done[u.v] = 1;
for (unsigned i = 0; i < G[u.v].size(); i++) {
Edge &e = G[u.v][i];
q.push((Node){ e.w, e.to });
}
}
cout << ans << endl;
}
7.线段树
//线段树
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=2e5+9;
int n,m;
ll sum[N<<2]/*4倍空间*/,tag[N<<2];
void pushup(int u){
sum[u]=sum[u<<1]+sum[u<<1|1];
}
void buildtree(int u,int ul,int ur){
if(ul==ur){//如果是叶节点
scanf("%ll",sum+u);
return;
}
int mid=ul+ur>>1;
buildtree(u<<1,ul,mid);
buildtree(u<<1|1,mid+1,ur);
pushup(u);
}
void update(int u,int ul,int ur,int mx){
tag[u]+=mx;
sum[u]+=(ll)mx*(ur-ul+1);
}
void pushdown(int u,int ul,int ur){
if(tag[u]){
int mid=ul+ur>>1;
update(u<<1,ul,mid,tag[u]);
update(u<<1|1,mid+1,ur,tag[u]);
tag[u]=0;
}
}
void modify(int u,int ul,int ur,int ml,int mr,int mx){
if(ml<=ul&&ur<=mr){
update(u,ul,ur,mx);
return;
}
pushdown(u,ul,ur);
int mid=ul+ur>>1;
if(ml<=mid)
modify(u<<1,ul,mid,ml,mr,mx);
if(mr>=mid+1)
modify(u<<1|1,mid+1,ur,ml,mr,mx);
pushup(u);
}
ll query(int u,int ul,int ur,int ml,int mr){
if(ml<=ul&&ur<=mr)
return sum[u];
pushdown(u,ul,ur);
int mid=ul+ur>>1;
ll s=0;
if(ml<=mid)
s+=query(u<<1,ul,mid,ml,mr);
if(mr>=mid+1)
s+=query(u<<1|1,mid+1,ur,ml,mr);
return s;
}
int main(){
scanf("%d%d",&n,&m);
buildtree(1,1,n);
while(m--){
int opt,x,y,z;
scanf("%d%d%d",&opt,&x,&y);
if(opt==0){
scanf("%d",&z);
modify(1,1,n,x,y,z);//修改函数
} else{
printf("%ll
",query(1,1,n,x,y));
}
}
}
8.树状数组
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 200005;
int n, m;
ll a[N], d[N], id[N];
int lowbit(int x){ return x&(-x); }
//算出x二进制的从右往左出现第一个1以及这个1之后的那些0组成数的二进制对应的十进制的数
//就是看区间和包括的数的个数
//-x代表x的负数,用对应的正数的补码来表示。
void modify(ll *t, int i, ll x) {
while (i <= n) { //不能越界
t[i] += x;
i += lowbit(i);
}
}
ll query(ll *t, int i) { //a[1]……a[x]的和
ll sum = 0;
while (i) {
sum += t[i];
i -= lowbit(i);
}
return sum;
}
ll q(int r) { return query(d, r) * (r + 1) - query(id, r); }
int main() {
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i++) {
scanf("%lld", &a[i]);
modify(d, i, a[i] - a[i - 1]);
modify(id, i, i * (a[i] - a[i - 1]));
}
while (m--) {
ll opt, x, y, z;
scanf("%lld%lld%lld", &opt, &x, &y);
if (opt == 0) {
scanf("%lld", &z);
modify(d, x, z);
modify(id, x, x * z);
modify(d, y + 1, -z);
modify(id, y + 1, (y + 1) * (-z));
} else
printf("%lld
", (q(y) - q(x - 1)));
}
return 0;
}
9.拓扑序
#include <bits/stdc++.h>
using namespace std;
const int N=1e5+5;
int n,m,du[N],f[N],cnt;
stack<int>s;
struct Edge{
int next,to;
}edge[N<<1];
int tot,head[N];
void add(int from,int to){
edge[++tot].next=head[from];
edge[tot].to=to;
head[from]=tot;
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++){
int u,v;
scanf("%d%d",&u,&v);
add(v,u);
du[u]++;
}
for(int i=1;i<=n;i++){
f[i]=1;
if(du[i]==0) s.push(i);
}
while(!s.empty()){
int u=s.top();
s.pop();
++cnt;
for(int i=head[u];i;i=edge[i].next ){
int v=edge[i].to;
f[v]=max(f[v],f[u]+1);
du[v]--;
if(du[v]==0) s.push(v);
}
}
if(cnt<n){
printf("-1
");
return 0;
}
long long ans=0;
for(int i=1;i<=n;i++)
ans+=f[i];
printf("%lld",ans);
}
10.并查集
#include <bits/stdc++.h>
using namespace std;
const int N = 50000 + 10;
int fa[N], val[N];
int find(int x) {
if (fa[x] == x)
return x;
int tmp = find(fa[x]);
(val[x] += val[fa[x]]) %= 3;
return fa[x] = tmp;
}
bool merge(int x, int y, int d) {
int fx = find(x), fy = find(y);
if (fx == fy)
return (val[x] - val[y] - d) % 3 == 0 ? 1 : 0;
fa[fy] = fx;
val[fy] = (val[x] - val[y] - d + 6) % 3;
return 1;
}
int main() {
int n, k, ans = 0;
scanf("%d%d", &n, &k);
for (int i = 1; i <= n; i++) fa[i] = i, val[i] = 0;
while (k--) {
int d, a, b;
scanf("%d%d%d", &d, &a, &b);
if (a > n || b > n || !merge(a, b, d - 1))
ans++;
}
printf("%d
", ans);
return 0;
}
11.高精加减乘
#include <bits/stdc++.h>
using namespace std;
//compare比较函数:相等返回0,大于返回1,小于返回-1
int compare(string str1,string str2) {
if(str1.length()>str2.length()) return 1;
else if(str1.length()<str2.length()) return -1;
else return str1.compare(str2);
}
//高精度加法
//只能是两个正数相加
string add(string str1,string str2) {
string str;
int len1=str1.length();
int len2=str2.length();
//前面补0,弄成长度相同
if(len1<len2) {
for(int i=1;i<=len2-len1;i++)
str1="0"+str1;
} else {
for(int i=1;i<=len1-len2;i++)
str2="0"+str2;
}
len1=str1.length();
int cf=0, temp;
for(int i=len1-1;i>=0;i--) {
temp=str1[i]-'0'+str2[i]-'0'+cf;
cf=temp/10;
temp%=10;
str=char(temp+'0')+str;
}
if(cf!=0)
str=char(cf+'0')+str;
return str;
}
//高精度减法
//只能是两个正数相减,而且要大减小
string sub(string str1,string str2) {
string str;
int tmp=str1.length()-str2.length();
int cf=0;
for(int i=str2.length()-1;i>=0;i--) {
if(str1[tmp+i]<str2[i]+cf) {
str=char(str1[tmp+i]-str2[i]-cf+'0'+10)+str;
cf=1;
} else {
str=char(str1[tmp+i]-str2[i]-cf+'0')+str;
cf=0;
}
}
for(int i=tmp-1;i>=0;i--) {
if(str1[i]-cf>='0') {
str=char(str1[i]-cf)+str;
cf=0;
} else {
str=char(str1[i]-cf+10)+str;
cf=1;
}
}
str.erase(0,str.find_first_not_of('0'));//去除结果中多余的前导0
return str;
}
//高精度乘法
//只能是两个正数相乘
string mul(string str1,string str2) {
string str;
int len1=str1.length();
int len2=str2.length();
string tem;
for(int i=len2-1;i>=0;i--) {
tem ="";
int temp=str2[i]-'0';
int t=0, cf=0;
if(temp!=0) {
for(int j=1;j<=len2-1-i;j++)
tem +="0";
for(int j=len1-1;j>=0;j--) {
t=(temp*(str1[j]-'0')+cf)%10;
cf=(temp*(str1[j]-'0')+cf)/10;
tem =char(t+'0')+tem;
}
if(cf!=0) tem =char(cf+'0')+tem;
}
str=add(str,tem);
}
str.erase(0,str.find_first_not_of('0'));
return str;
}
//高精度除法
//两个正数相除,商为quotient,余数为residue
//需要高精度减法和乘法
void div(string str1,string str2,string &quo,string &resi) {
quo =resi ="";//清空
if(str2=="0") {//判断除数是否为0
quo =resi ="ERROR";
return;
}
if(str1=="0") {//判断被除数是否为0
quo =resi ="0";
return;
}
int res=compare(str1,str2);
if(res<0) {
quo ="0";
resi =str1;
return;
} else if(res==0) {
quo ="1";
resi ="0";
return;
} else {
int len1=str1.length();
int len2=str2.length();
string tem ;
tem .append(str1,0,len2-1);
for(int i=len2-1;i<len1;i++) {
tem =tem +str1[i];
tem .erase(0,tem .find_first_not_of('0'));
if(tem .empty())
tem ="0";
for(char ch='9';ch>='0';ch--) {//试商
string str,tmp;
str=str+ch;
tmp=mul(str2,str);
if(compare(tmp,tem )<=0) {//试商成功
quo =quo +ch;
tem =sub(tem ,tmp);
break;
}
}
}
resi =tem ;
}
quo .erase(0,quo .find_first_not_of('0'));
if(quo .empty())
quo ="0";
}
int main() {
string a, b, c, d;
cin >> a >> b;
div(a, b, c, d);
cout << c;
}
12.压位+floyd
#include <bits/stdc++.h>
using namespace std;
const int N = 2005;
int f[N][N], n;
int main() {
scanf("%d", &n);
for (int i = 0; i < n; i++) {
char a[N];
scanf("%s", &a);
a[i] = '1'; //对角线上的
for (int j = 0; j < n; j++)
if (a[j] - '0' == 1) {
int k = j % 32;
f[i][j / 32] |= 1 << k; // 1左移k位,加入集合
}
}
for (int k = 0; k < n; k++) {
for (int i = 0; i < n; i++) {
if (i == k)
continue;
if (!(f[i][k / 32] & 1 << (k % 32))) // i能到达k
continue;
for (int j = 0; j <= n / 32; j++) f[i][j] = f[k][j] | f[i][j]; //从k能到j的并上从i到j的
}
}
for (int i = 0; i < n; i++) {
for (int j = 0; j <= n / 32; j++)
for (int k = 0; k <= 31 && j * 32 + k < n; k++) //遍历k位
putchar(((f[i][j] >> k) & 1) + '0'); //看每一位能否到达
printf("
"); // puts("");换行
}
}
13.Lucas
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 200005;
ll a[N];
int p;
int read() {
int x = 0, f = 1;
char ch = getchar();
while (ch > '9' || ch < '0') {
if (ch == '-') f= -1;
ch = getchar();
}
while (ch >= '0' && ch <= '9') {
x = (x << 3) + (x << 1) + ch - '0';
ch = getchar();
}
return x * f;
}
ll pow(ll a, ll b, ll mod) {
ll ans = 1;
while (b) {
if (b & 1)
ans = ans * a % mod;
b >>= 1;
a = a * a % mod;
}
return ans;
}
ll C(ll n, ll m) {//求阶乘
ll ans = 1;
for (int i = n - m + 1; i <= n; i++)
ans = ans * i % p;
return ans;
}
ll Lucas(ll n, ll m) { //卢卡斯定理
if (!m) return 1;
if (n < p && m < p)
return C(n, m) * pow(a[m], p - 2, p) % p;
return Lucas(n % p, m% p) * Lucas(n / p, m / p) % p;
}
int main() {
int T = read();
while (T--) {
int n = read(), m = read();
p = read();
a[0] = 1;
for (int i = 1; i <= m; i++)
a[i] = (a[i - 1] * i) % p; //预处理阶乘到m
cout << Lucas(n, m) << endl;
}
}
14.LCA
#include <bits/stdc++.h>
using namespace std;
const int N = 20050;
vector<int> to[N];
int n,m,f[N][20], d[N], bu[N][N], cnt[N], ans[N], fa[N];
void insert(int u, int v) {
to[u].push_back(v);
}
void dfs(int u, int h) {
for (unsigned int i = 0; i < to[u].size(); i++) {
int v = to[u][i];
if (v != fa[u]) {
d[v] = h;
cnt[v] = cnt[u] + bu[v][u];
fa[v] = u;
dfs(v, h + 1);
}
}
}
void init() {
for (int i = 1; i <= n; i++)
f[i][0] = fa[i];
for (int j = 1; j <= 19; j++)
for (int i = 1; i <= n; i++)
f[i][j] = f[f[i][j - 1]][j - 1];
}
int lca(int u, int v) {
if (d[u] != d[v]) {
if (d[u] > d[v])
swap(u, v);
int x = d[v] - d[u], j = 0;
while (x) {
if (x & 1)
v = f[v][j];
x >>= 1;
j++;
}
}
if (u == v)
return u;
for (int i = 19; i >= 0; i--) {
if (f[u][i] != f[v][i]) {
u = f[u][i];
v = f[v][i];
}
}
return fa[u];
}
int main() {
scanf("%d%d",&n,&m);
for (int i = 1; i < n; i++) {
int b, c, t;
scanf("%d%d%d",&b,&c,&t);
insert(c, b);
insert(b, c);
bu[b][c] = t;
bu[c][b] = t;
}
d[1] = 1;
dfs(1, 2);
init();
for (int i = 1; i <= m; i++) {
int x, y;
scanf("%d%d",&x,&y);
ans[i] = cnt[x] + cnt[y] - 2 * cnt[lca(x, y)];
}
for (int i = 1; i <= m; i++)
cout << ans[i] << endl;
}
15.二分
#include<bits/stdc++.h>
#define N 2000005
using namespace std;
int n,m,l,ans,a[N];
int judge(int x){
int s=0,num=0;
for(int i=1;i<=n;i++){
if(a[i]-s<x) num++;
else s=a[i];
}
if(num>m) return 0;
return 1;
}
int main(){
scanf("%d%d%d",&l,&n,&m);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
a[n+1]=l;
int le=0,ri=l;
while(le<=ri){
int mid=le+ri>>1;
if(judge(mid)){
le=mid+1;
ans=mid;
}
else ri=mid-1;
}
printf("%d",ans);
}
16.堆
#include <bits/stdc++.h>
using namespace std;
const int N = 100010;
int n, m,a[N]; // n表示堆里还有多少个节点,n是变的,所以弄个不变的m
void update(int x) { //左移代表乘以二,就代表左儿子 //x<<1|1表示乘以二加一
if ((x << 1) > n)
return;
int y = x << 1; //如果只有一个儿子,y就是唯一的儿子,如果有两个,y就是更大的那个儿子
if ((y | 1) <= n && a[y | 1] < a[y])
y = y | 1;
if (a[y] >= a[x])
return;
swap(a[x], a[y]);
update(y);
}
int main() {
scanf("%d %d", &n, &m);
for (int i = 1; i <= n; i++) scanf("%d", &a[i]);
for (int i = n >> 1; i >= 1; i--) update(i);
for (int i = 1; i <= m; i++) {
int temp;
scanf("%d", &temp);
if (temp == 1) {
scanf("%d", &a[++n]);
for (int i = n >> 1; i >= 1; i = i >> 1) update(i);
} else if (temp == 2) {
printf("%d", a[1]);
puts("");
swap(a[1], a[n]);
n--;
update(1);
}
}
}
17.单调队列
#include <bits/stdc++.h>
using namespace std;
const int N = 1000005;
int ai[N], maxq[N], minq[N];
int n, m, c, ahead, ihead, ansn, atail = 1, itail = 1;
int main() {
scanf("%d%d%d",&n, &m, &c);
for (int i = 1; i <= n; i++) scanf("%d", ai + i);
for (int i = 1; i <= n; i++) {
while (ahead >= atail && ai[maxq[ahead]] <= ai[i]) --ahead;
++ahead;
maxq[ahead] = i;
while (ihead >= itail && ai[minq[ihead]] >= ai[i]) --ihead;
++ihead;
minq[ihead] = i;
if (maxq[atail] <= i - m) ++atail;
if (minq[itail] <= i - m) ++itail;
if (i >= m)
if (ai[maxq[atail]] - ai[minq[itail]] <= c) {
printf("%d
", i - m + 1);
++ansn;
}
}
if(!ansn)
printf("NONE");
}
18.欧几里得(辗转相除)
ll gcd(ll a, ll b) { return !b ? a : gcd(b, a%b); }
19.扩展欧几里得
青蛙的约会:https://www.luogu.org/problem/P1516
int exgcd(int a,int b,int &x,int &y){
if(b == 0){
x = 1, y = 0;
return a;
}
int ret = exgcd(b, a%b, x, y);
int tmp = x;
x = y;
y = tmp - a/b*y;
return ret;
}
20.差分、前缀和
·区间修改后询问 http://oj.ipoweru.cn/problem/24200
#include <bits/stdc++.h>
using namespace std;
typedef long long lld;
const int N = 1e6 + 9;
int n, m, q;
lld a[N], d[N], s[N];
int main() {
scanf("%d%d%d", &n, &m, &q);
for (int i = 1; i <= n; ++i) scanf("%lld", &a[i]);
for (int i = 1; i <= n; ++i) d[i] = a[i] - a[i - 1];
for (int i = 1, x, y, z; i <= m; ++i) {
scanf("%d%d%d", &x, &y, &z);
d[y + 1] -= z;
d[x] += z;
}
for (int i = 1; i <= n; ++i) a[i] = a[i - 1] + d[i];
for (int i = 1; i <= n; ++i) s[i] = s[i - 1] + a[i];
for (int i = 1, x, y; i <= q; ++i) {
scanf("%d%d", &x, &y);
printf("%lld
", s[y] - s[x - 1]);
}
}
21.分解质因数
#include <bits/stdc++.h>
#define int long long
using namespace std;
int T, n, t, sta[1000000], tot;
int mul(int a, int b, int mod) {
int ans = 0;
while (b) {
if (b & 1)
ans = (ans + a) % mod;
a = (a + a) % mod;
b >>= 1;
}
return ans;
}
int g(int x, int mod, int c) { return (mul(x, x, mod) + c) % n; }
int qpow(int a, int b, int mod) {
int ans = 1;
while (b) {
if (b & 1)
ans = mul(ans, a, mod);
b >>= 1;
a = mul(a, a, mod);
}
return ans;
}
bool MillerRabin(int n) {
if (n == 2)
return 1;
if (n < 2 || !(n & 1))
return 0;
int m = n - 1, k = 0;
while (!(m & 1)) {
k++;
m >>= 1;
}
for (int i = 1; i <= 3; i++) {
int a = rand() % (n - 1) + 1;
int x = qpow(a, m, n);
int y;
for (int j = 1; j <= k; j++) {
y = mul(x, x, n);
if (y == 1 && x != 1 && x != n - 1)
return 0;
x = y;
}
if (y != 1)
return 0;
}
return 1;
}
int check(int n, int c) {
int a = 2, b = a,p = 1;
do {
a = g(a, n, c);
b = g(g(b, n, c), n, c);
p = __gcd(abs(a - b), n);
if (p != 1) break;
} while (a != b);
if (a == b) return 0;
else return p;
}
void solve(int n) {
while (n % 2 == 0) { // n为偶数
n /= 2;
sta[++tot] = 2;
}
if (n == 1)
return;
if (MillerRabin(n))
sta[++tot] = n;
else {
int d = n;
int i = 1;
while (i++) {
d = check(n, i);
if (d != n)
break;
}
solve(d);
solve(n / d);
}
}
signed main() {
srand(time(0));
cin >> T;
while (T--) {
tot = 0;
cin >> n;
solve(n);
sort(sta + 1, sta + tot + 1);
for (int i = 1; i <= tot; i++) {
cout << sta[i] << " ";
}
cout << endl;
}
}
22.卷积式
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 3505;
int T, n, m, q;
ll f[N], g[N];
void work(int n) {
if (n == 1) return;
if (!(n & 1)) {//n&1判断奇偶.当n为奇数时,返回1;当n为偶数时,返回0
//为偶数
work(n / 2);
for (int i = 0; i <= m; i++) {
g[i] = 0;
for (int j = 0; j <= i; j++)
g[i] += f[j] % q * f[i - j] % q;
g[i] %= q;
}
for (int i = 0; i <= m; i++)
f[i] = g[i];
} else { //奇数
work(n - 1);
for (int i = 1; i <= m; i++) {
g[i] = f[i - 1] % q + f[i] % q;
g[i] %= q;
}
for (int i = 1; i <= m; i++)
f[i] = g[i];
}
}
signed main() {
scanf("%d",&T);
while (T--) {
scanf("%d%d%d",&n,&m,&q);
memset(f, 0, sizeof f);
f[0] = f[1] = 1;
work(n);
for (int i = 0; i <= m; i++)
printf("%lld ",f[i] % q);
puts("");
}
}
23.容斥原理
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int N=2003;
int n, m, f[N][N], a[N], c[N];
ll p, ans;
void getpre() {
for (int i = 0; i <= n + 1; i++) {
f[i][0] = 1;
f[i][i] = 1;
}
for (int i = 1; i <= n + 1; i++)
for (int j = 1; j <= i; j++)
f[i][j] = (f[i - 1][j] + f[i - 1][j - 1]) % p;
}
void dfs(int k, int s, int sum) {
if (sum <= 0) return;
if (k == m + 1) {
ans = (ans + s * f[sum - 1][m - 1] % p + p) % p;
return;
}
dfs(k + 1, s, sum);
dfs(k + 1, -s, sum - c[k] - 1);
}
int main() {
scanf("%d%d%lld", &m, &n, &p);
int num = 0;
getpre();
for (int i = 1; i <= m; i++) {
scanf("%d%d",&a[i],&c[i]);
c[i] -= a[i];
num += a[i];
}
dfs(1, 1, n + m - num);
printf("%lld", ans);
}
24.重载
//重载运算符比较大小
struct node { int len;
bool operator <(const node &a)const {//重载<操作符。可以对两个node使用<操作符进行比较
return len<a.len;
}
};