ACM常用模板V2.0
vector, 变长数组,倍增的思想
size() 返回元素个数
empty() 返回是否为空
clear() 清空
front()/back()
push_back()/pop_back()
begin()/end()
[]
支持比较运算,按字典序
pair<int, int>
first, 第一个元素
second, 第二个元素
支持比较运算,以first为第一关键字,以second为第二关键字(字典序)
string,字符串
size()/length() 返回字符串长度
empty()
clear()
substr(起始下标,(子串长度)) 返回子串
c_str() 返回字符串所在字符数组的起始地址
queue, 队列
size()
empty()
push() 向队尾插入一个元素
front() 返回队头元素
back() 返回队尾元素
pop() 弹出队头元素
priority_queue, 优先队列,默认是大根堆
push() 插入一个元素
top() 返回堆顶元素
pop() 弹出堆顶元素
定义成小根堆的方式:priority_queue<int, vector<int>, greater<int>> q;
stack, 栈
size()
empty()
push() 向栈顶插入一个元素
top() 返回栈顶元素
pop() 弹出栈顶元素
deque, 双端队列
size()
empty()
clear()
front()/back()
push_back()/pop_back()
push_front()/pop_front()
begin()/end()
[]
set, map, multiset, multimap, 基于平衡二叉树(红黑树),动态维护有序序列
size()
empty()
clear()
begin()/end()
++, -- 返回前驱和后继,时间复杂度 O(logn)
set/multiset
insert() 插入一个数
find() 查找一个数
count() 返回某一个数的个数
erase()
(1) 输入是一个数x,删除所有x O(k + logn)
(2) 输入一个迭代器,删除这个迭代器
lower_bound()/upper_bound()
lower_bound(x) 返回大于等于x的最小的数的迭代器
upper_bound(x) 返回大于x的最小的数的迭代器
map/multimap
insert() 插入的数是一个pair
erase() 输入的参数是pair或者迭代器
find()
[] 注意multimap不支持此操作。 时间复杂度是 O(logn)
lower_bound()/upper_bound()
unordered_set, unordered_map, unordered_multiset, unordered_multimap, 哈希表
和上面类似,增删改查的时间复杂度是 O(1)
不支持 lower_bound()/upper_bound(), 迭代器的++,--
bitset, 圧位
bitset<10000> s;
~, &, |, ^
>>, <<
==, !=
[ ]
count() 返回有多少个1
any() 判断是否至少有一个1
none() 判断是否全为0
set() 把所有位置成1
set(k, v) 将第k位变成v
reset() 把所有位变成0
flip() 等价于~
flip(k) 把第k位取反
字符串转换整数
atoi(char);把字符串(字符char)转换成整型数的一个函数
stoi;把字符串(string)转换成整数
typedef unsigned long long ll;
ll stoi(char *ss,ll l,ll r)//自己写一个字符串转整数。想知道为什么cstring里包含的stoi()用不了
{
ll res=0;
if(l>r)return 0;
for (ll i=l;i<=r;i++)
{
res*=10;
res+=ss[i]-'0';
}
return res;
}
数据结构
KMP
const int N = 1e6+7;int ne[N];
string s1,s2;int len1 ,len2;void init(){
int ix1 = 0,ix2= -1;
ne[0] = -1;
while(ix1<len1){
if(ix2==-1||s1[ix2]==s1[ix1]){
ne[++ix1]=++ix2;
}
else ix2 = ne[ix2];
}}void KMP(){
int ix1 = 0,ix2 =0;
while(ix1<len2){
if(ix2==-1||s2[ix1]==s1[ix2]) ix1++,ix2++;
else ix2 = ne[ix2];
if(ix2 == len1){
cout<< ix1-len1<<" " ;
}
}}int main(){
int n;
cin>>n>>s1>>n>>s2;
len1 = s1.length();
len2 = s2.length();
init();
KMP();
return 0;}
const int N = 1e6+7;int son[N][26],cnt[N],idx=0;void insert(string str){
int p = 0;
for(int i = 0;str[i];i++){
int u = str[i] - 'a';
if(!son[p][u]) son[p][u] = ++idx;
p = son[p][u];
}
cnt[p]++;}int query(string str){
int p = 0;
for(int i = 0;str[i];i++){
int u = str[i] - 'a';
if(!son[p][u]) return 0;
p = son[p][u];
}
return cnt[p];}
AC自动机
#include<bits/stdc++.h>
using namespace std;
const int N = 1e6+7;
int trie[N][26]; //字典树代表节点i的儿子j字母的节点编号
int val[N]; //附加信息
int fail[N]; //失配指针
int cnt = 0; //字典树节点的编号
int f(char s){return s-'a';}
void insert(string s) //建立trie
{ int u = 0; //从根节点开始遍历
int ch;
for(int i=0;i<s.length();i++){ //遍历所有的字母
ch = f(s[i]);
if(trie[u][ch]==0){
trie[u][ch] = ++cnt;
// printf("%d %d %d",u,ch,cnt);
}//不存在就创建新节点
u = trie[u][ch]; //更新父亲节点
}
val[u]++; //在叶子标记为单词末尾
//if(val[u]) cout<<val[u]<<" "<<u<<" ";
}
void init_fail(){ //bfs遍历
int u = 0;
queue<int> q;
fail[u] = 0;
for(int i = 0;i<26;i++){ //先把第一层的所有字母放入队列
if(trie[u][i]) {
fail[trie[u][i]] = u;
q.push(trie[u][i]);
}
}
while(!q.empty()){ //类似bfs
int rt = q.front();
q.pop();
for(int i =0;i<26;i++){
if(trie[rt][i]){
fail[trie[rt][i]] = trie[fail[rt]][i];
// 节点的失败指针指向(((他父亲节点)的失败指针所指向的那个节点)的下一个节点)
q.push(trie[rt][i]);
}
else trie[rt][i] = trie[fail[rt]][i];
}
}
}
int ask(string s){
int u = 0;
int ans = 0;
int ch;
for(int i=0;i<s.length();i++){
ch = f(s[i]);
// cout<<ch<<" ";
//printf("%d %d\n",u,ch);
if(trie[u][ch]){
if(val[trie[u][ch]]) {
ans+=val[trie[u][ch]];
val[trie[u][ch]] = 0;
//cout<<ans<<endl;
}
u = trie[u][ch];
}
else {
u = fail[trie[u][ch]];
}
}
return ans ;
}
int main(){
int n;
cin>>n;
while(n--){
string s;
cin>>s;
insert(s);
}
init_fail();
string k;
cin>>k;
cout<<ask(k)<<endl;
return 0;
}
树链剖分求LCA
#include<bits/stdc++.h>
using namespace std;
const int N = 1e6+7;
int d[N],f[N],size[N],son[N],top[N];
int head[N],ecnt = 0;
struct edge{
int to,next;
}e[N];
void add(int u,int v){
e[++ecnt].to=v;
e[ecnt].next=head[u];
head[u]=ecnt;
}
void dfs1(int x,int fath){
size[x]=1;d[x]=d[fath]+1;
son[x]=0;f[x]=fath;
for(int i = head[x];i;i=e[i].next){
int to = e[i].to;
if(to==fath) continue;
dfs1(to,x);
size[x]+=size[to];
if(size[son[x]]<size[to]) son[x] = to;
}
}
void dfs2(int x,int topx){
top[x] = topx;
if(son[x]!=0) dfs2(son[x],topx);
for(int i =head[x];i;i=e[i].next){
if(e[i].to!=f[x] && e[i].to!=son[x])
dfs2(e[i].to,e[i].to);
}
}
int lca(int x,int y){
while(top[x]!=top[y]){
if(d[top[x]]<d[top[y]]) swap(x,y);
x = f[top[x]];
}
return d[x]<d[y]?x:y;
}
int main(){
int n,m,s;
cin>>n>>m>>s;
for(int i=0;i<n-1;i++){
int u,v;
cin>>u>>v;
add(u,v);
add(v,u);
}
dfs1(s,0);
dfs2(s,s);
while(m--){
int x,y;
cin>>x>>y;
cout<<lca(x,y)<<"\n";
}
return 0;
}
#include<bits/stdc++.h>
using namespace std;
const int N = 5000000;
int head[N];
int lg[N];
struct edge{
int to,next;
}e[N*4];
int fa[N][30],ecnt=1;
int dep[N];
void addedge(int u,int v){
e[ecnt].to=v;
e[ecnt].next=head[u];
head[u] = ecnt;
ecnt++;
}
void dfs(int son,int father){
dep[son]=dep[father]+1;
fa[son][0] = father;
for(int i = 1;i<=lg[dep[son]];i++){
fa[son][i]=fa[fa[son][i-1]][i-1];
}
for(int i = head[son];i;i=e[i].next){
if(e[i].to!=father) dfs(e[i].to,son);
}
}
int LCA(int x,int y){
if(dep[y]>dep[x]) swap(x,y);
while(dep[x]>dep[y]){
x=fa[x][lg[dep[x]-dep[y]]-1];
}
if(x==y) return x;
for(int i=lg[dep[x]]-1;i>=0;i--)
if(fa[x][i]!=fa[y][i])
x=fa[x][i],y=fa[y][i];
return fa[x][0];
}
int main(){
int n,m,s;
cin>>n>>m>>s;
for(int i = 1; i <= n; ++i)
lg[i] = lg[i-1] + (1 << lg[i-1] == i);
for(int i = 0;i<n-1;i++){
int u,v;
cin>>u>>v;
addedge(u,v);
addedge(v,u);
}
dfs(s,0);
for(int i = 0;i<m;i++){
int a,b;
cin>>a>>b;
cout<<LCA(a,b)<<endl;
}
return 0;
}
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int maxn = 3001;
const int maxm = 3001;
int a[maxn][maxm],h[maxn][maxm];
int st[maxn];
int cnt[maxn][maxn];
int main(){
int n,m;
scanf("%d%d",&n,&m);
for( int i = 1;i <= n;i++ ){
for( int j = 1;j <= m;j++ ){
cin>>a[i][j];
}
}
for( int i = 1;i <= m;i++ ){
for( int j = 1;j <= n;j++ ){
if( a[j][i]==0 ) h[j][i] = 0;
else h[j][i] = h[j-1][i] + 1;
}
}
LL ans = 0;
for( int i = 1;i <= n;i++ ){
int top = 0;
for( int j = 1;j <= m;j++ ){
while( top && h[i][j] < h[i][ st[top] ] )top--;
st[++top] = j;
if( top > 1 )cnt[i][j] += cnt[i][ st[top-1] ];
cnt[i][j] += 1LL * (j - st[top-1])* h[i][j];
ans += cnt[i][j];
}
}
printf("%lld\n",ans);
return 0;}
带权并查集
食物链
动物王国中有三类动物 A,B,C,A 吃 B,B 吃 C,C 吃 A。现有 N 个动物,以 1∼N 编号。
每个动物都是 A,B,C 中的一种,但是我们并不知道它到底是哪一种。
第一种说法是 1 X Y,表示 X 和 Y 是同类。
第二种说法是 2 X Y,表示 X 吃 Y。
此人对 N 个动物,用上述两种说法,一句接一句地说出 K 句话,这 K 句话有的是真的,有的是假的。
当一句话满足下列三条之一时,这句话就是假话,否则就是真话。
当前的话与前面的某些真的话冲突,就是假话;
当前的话中 X 或 Y 比 N 大,就是假话;
当前的话表示 X 吃 X,就是假话。
你的任务是根据给定的 N 和 K 句话,输出假话的总数。
#include<bits/stdc++.h>
using namespace std;
const int N = 1e6+7;
int A[N],d[N];
int find(int x){
if(A[x]!=x) {
int t = find(A[x]);
d[x] += d[A[x]];
A[x] = t;
}
return A[x];
}
int main(){
int n,m;
cin>>n>>m;
for(int i = 1;i<=n;i++) A[i] = i;
int res = 0;
for(int i = 1;i<=m;i++){
int t,x,y;
cin>>t>>x>>y;
int px = find(x),py = find(y);
if(x>n||y>n) res++;
else {
if(t==1) {
if(px==py&&(d[x]-d[y])%3)res++;
else if(px!=py){
A[px] =py;
d[px] = d[y]-d[x];
}
}
else {
if(px==py&&(d[x]-d[y]-1)%3) res++;
else if(px!=py){
A[px] = py;
d[px] = d[y]-d[x]+1;
}
}
}
}
cout<<res<<endl;
return 0;
}
841. 字符串哈希
给定一个长度为 n 的字符串,再给定 m 个询问,每个询问包含四个整数 l1,r1,l2,r2,请你判断 [l1,r1] 和 [l2,r2] 这两个区间所包含的字符串子串是否完全相同。
#include<bits/stdc++.h>
#include<bits/stdc++.h>
using namespace std;const int N = 1e6+7;
typedef unsigned long long ull;
const int I = 131;
ull p[N]={1},h[N],n,q;char s[N];
ull check(int l,int r){
return h[r]-h[l-1]*p[r-l+1];}int main(){
scanf("%d%d%s",&n,&q,s+1);
for(int i = 1;i<=n;i++){
p[i] = p[i-1]*I;
h[i] = I*h[i-1] + s[i];
}
while(q--){
int l,r,ll,rr;
cin>>l>>r>>ll>>rr;
if(check(l,r)==check(ll,rr)) cout<<"Yes"<<endl;
else cout<<"No\n";
}
return 0;}
线段树
#include<bits/stdc++.h>using namespace std;const int N = 1e5+7;typedef long long ll;
ll A[N];
ll n,m,p;struct TREE{
ll val,lazy=0,mul=1;}tree[N*4];void pushup(ll rt){
tree[rt].val = (tree[rt*2].val+tree[rt*2+1].val)%p;} void build(ll l,ll r,ll rt){
if(l==r) {
tree[rt].val = A[l];
return ;
}
ll mid = (l+r)/2;
build(l,mid,rt*2);build(mid+1,r,rt*2+1);
pushup(rt);}void pushdown(ll l,ll r,ll rt){
tree[rt*2].val = (tree[rt].mul*tree[rt*2].val+tree[rt].lazy*l)%p;
tree[rt*2+1].val = (tree[rt].mul*tree[rt*2+1].val+tree[rt].lazy*r)%p;
tree[rt*2].mul = (tree[rt].mul*tree[rt*2].mul)%p;
tree[rt*2+1].mul = (tree[rt].mul*tree[rt*2+1].mul)%p;
tree[rt*2].lazy = (tree[rt*2].lazy*tree[rt].mul+tree[rt].lazy)%p;
tree[rt*2+1].lazy = (tree[rt*2+1].lazy*tree[rt].mul+tree[rt].lazy)%p;
tree[rt].lazy = 0;
tree[rt].mul = 1; }void updata1(ll L,ll R,ll C,ll l,ll r,ll rt){
if(l>=L&&r<=R){
tree[rt].lazy = (C+tree[rt].lazy)%p;
tree[rt].val = (tree[rt].val+C*(r-l+1))%p;
return;
}
ll mid = (l+r)/2;
pushdown(mid-l+1,r-mid,rt);
if(mid>=L) updata1(L,R,C,l,mid,rt*2);
if(mid<R) updata1(L,R,C,mid+1,r,rt*2+1);
pushup(rt); }void updata2(ll L,ll R,ll C,ll l,ll r,ll rt){
if(l>=L&&r<=R){
tree[rt].lazy = tree[rt].lazy*C%p;
tree[rt].mul = tree[rt].mul*C%p;
tree[rt].val = (tree[rt].val*C)%p;
return;
}
ll mid = (l+r)/2;
pushdown(mid-l+1,r-mid,rt);
if(mid>=L) updata2(L,R,C,l,mid,rt*2);
if(mid<R) updata2(L,R,C,mid+1,r,rt*2+1);
pushup(rt); }
ll ask(ll L,ll R,ll l,ll r,ll rt){
if(l>=L&&r<=R){
return tree[rt].val%p;
}
ll mid = (l+r)/2;
if(l>R||r<L)return 0;
pushdown(mid-l+1,r-mid,rt);
return (ask(L,R,l,mid,rt*2)+ask(L,R,mid+1,r,rt*2+1))%p;}
int main(){
cin>>n>>p;
for(ll i = 1;i<=n;i++){
cin>>A[i];
}
cin>>m;
build(1,n,1);
while(m--){
ll x,y,a,c;
cin>>a>>x>>y;
if(a==1) {
cin>>c;
updata2(x,y,c,1,n,1);
}
else if(a==2){
cin>>c;
updata1(x,y,c,1,n,1);
}
else cout<<ask(x,y,1,n,1)%p<<'\n';
}
return 0;}
#include <bits/stdc++.h>
using namespace std;
const int N = 1e6+7;
typedef long long ll;
int tr[N],n;
void add(int ix,int x){
for(int i = ix;i<=n;i+=(i&-i)){
tr[i] += x;
}
}
int ask(int ix){
int res = 0;
for(int i = ix;i>0;i-=(i&-i)){
res += tr[i];
}
return res;
}
struct node{
int l,r,i;
bool operator<(const node a)const{
return l<a.l;
}
}B[N];
int pos[N];
int ans[N],A[N];
int main(){
//ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr);
int T;
cin>>T;
while(T--){
int m;
scanf("%d%d",&n,&m);
for(int i = 0;i<=4*n;i++) tr[i] = 0;
for(int i = 1;i<=n;i++) {
scanf("%d",&A[i]);
pos[A[i]] = i;
}
for(int i = 0;i<m;i++){
int l,r;scanf("%d%d",&l,&r);
B[i] = {l,r,i};
}
sort(B,B+m);
pos[0] = n + 1, pos[n + 1] = n + 1;
for(int i = 1;i<=n;i++){
if(pos[A[i]-1]>i&&pos[A[i]+1]>i)
add(i,1);
if(pos[A[i]-1]<i&&pos[A[i]+1]<i)
add(i,-1);
}
int ix = 0;
for(int i = 1;i<=n;i++){
while(ix<m&&i==B[ix].l){
ans[B[ix].i] = ask(B[ix].r);
ix++;
}
add(i,-1);
if(pos[A[i]+1]>i) add(pos[A[i]+1],1);
if(pos[A[i]-1]>i) add(pos[A[i]-1],1);
}
for(int i = 0;i<m;i++){
printf("%d\n",ans[i]);
}
}
return 0;
}
莫队
区间求不同的数+单点修改
#include<bits/stdc++.h>
using namespace std;
const int N = 1e6+7;
typedef long long ll;
int n,m;
int block;
int A[N],cnt[N],cur = 0,ans[N];
inline int read(){
int a=0,f=0;char c=getchar();
for(;c<'0'||c>'9';c=getchar())if(c=='-')f=1;
for(;c>='0'&&c<='9';c=getchar())a=a*10+c-'0';
return f?-a:a;
}
struct node{
ll l,r,id,t;
}qq[N];
struct nod{
int l,r;
}qr[N];
int cntqq,cntqr;
bool cmp (const node &a, const node &b)
{
return a.l / block == b.l / block ? a.r / block == b.r / block ? a.t < b.t : a.r < b.r : a.l < b.l;
}
inline void add(int i,int x){
if(x==1){
cur += !cnt[A[i]]++;
}
else cur -= !(--cnt[A[i]]);
}
inline void upd(int ll,int rr,int t){
if(ll <= qr[t].l && rr >= qr[t].l){
add(qr[t].l,-1);
cur += !cnt[qr[t].r]++;
}
A[qr[t].l] = A[qr[t].l] ^ qr[t].r;
qr[t].r = A[qr[t].l] ^ qr[t].r;
A[qr[t].l] = A[qr[t].l] ^ qr[t].r;
}
int main(){
//ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr);
scanf("%d%d",&n,&m);
block = pow(n,0.666);
for(int i = 1;i<=n;i++) scanf("%lld",A+i);
for(int i = 0;i<m;i++){
int l,r;
char ch[5];
scanf("%s%d%d",ch,&l,&r);
if(ch[0]=='Q'){
qq[cntqq] = {l,r,cntqq,cntqr};
cntqq++;
}
else {
qr[++cntqr] = {l,r};
}
}
sort(qq,qq+cntqq);
int l = 1,r = 0,t = 0;
for(int i = 0;i<cntqq;i++){
int ll = qq[i].l;
int rr = qq[i].r;
int tt = qq[i].t;
while(l>ll) add(--l,1);
while(r>rr) add(r--,-1);
while(l<ll) add(l++,-1);
while(r<rr) add(++r,1);
while(t<tt) upd(ll,rr,++t);
while(t>tt) upd(ll,rr,t--);
ans[qq[i].id] = cur;
}
for(int i = 0;i<cntqq;i++){
printf("%d\n",ans[i]);
}
return 0;
}
克鲁斯卡尔重构树
求路径最大值最小
#include<bits/stdc++.h>
using namespace std;
const int N = 1e6+7;
typedef long long ll;
int A[N];
vector<int> v[N];
int sz[N],dep[N],son[N],fa[N],top[N];
int find(int x){
if(x == A[x]) return A[x];
else return A[x] = find(A[x]);
}
void dfs(int u,int f){
dep[u] = dep[f] + 1;
sz[u] = 1;
fa[u] = f;
for(int i : v[u]){
if(i == f) continue;
dfs(i,u);
sz[u] += sz[i];
if(sz[son[u]]<sz[i]) son[u] = i;
}
}
void dfs1(int u,int topx){
top[u] = topx;
if(son[u]) dfs1(son[u],topx);
for(int i : v[u]){
if(i == fa[u] || son[u] == i) continue;
dfs1(i,i);
}
}
int LCA(int a,int b){
while(top[a] != top[b]){
if(dep[top[a]] < dep[top[b]]) swap(a,b);
a = fa[top[a]];
}
return dep[a]<dep[b]?a:b;
}
struct node{
int a,b,c;
bool operator < (const node p) const {
return c < p.c;
}
}e[N];
int key[N];
int main(){
ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr);
int n,m;
cin>>n>>m;
for(int i = 1;i<=m;i++){
int a,b,c;
cin>>a>>b>>c;
e[i] = {a,b,c};
}
sort(e+1,e+m+1);
int k = n;
for(int i = 1;i<=n*2;i++) A[i] = i;
for(int i = 1;i<=m;i++){
int a = e[i].a , b =e[i].b,c =e[i].c;
int na = find(a);
int nb = find(b);
if(na!=nb){
k++;
A[nb] = A[na] = k;
v[na].push_back(k);
v[k].push_back(na);
v[nb].push_back(k);
v[k].push_back(nb);
key[k] = c;
}
}
for(int i = k;i;i--)if(!sz[i]) dfs(i,i),dfs1(i,i);
int q;
cin>>q;
while(q--){
int x,y;
cin>>x>>y;
if(find(x)!=find(y)) {
cout<<"impossible\n";
}
else {
cout<<key[LCA(x,y)]<<'\n';
}
}
return 0;
}
二.数学
欧拉函数
求单个
const int N = 1e6+7;
int main(){
int T;
cin>>T;
while(T--){
ll x;
cin>>x;
ll res = x;
for(ll i = 2;i<=x/i;i++){
if(x%i==0){
while(x%i==0) x/=i;
res = res/i*(i-1);
}
}
if(x>1) res = res/x*(x-1);
cout<<res<<endl;
}
return 0;}
线性求
void get_eulers(int n){
phi[1] = 1;
for (int i = 2; i <= n; i++)
{
if (!st[i])
{
primes[cnt++] = i;
phi[i] = i - 1;
}
for (int j = 0; primes[j] <= n / i; j++)
{
st[primes[j] * i] = true;
if (i % primes[j] == 0)
{
phi[primes[j] * i] = phi[i] * primes[j];
break;
}
phi[primes[j] * i] = phi[i] * (primes[j] - 1);
}
求逆元
1.费马小定理 inv[i] = pow(i,p-2) p为质数
2.exgcd
ll exgcd(ll a,ll b,ll & x,ll &y){
if(!b){
x = 1;
y = 0;
return a;
}
ll d = exgcd(b,a%b,y,x);
y -= x*(a/b);
return d;}
3 . 线性递推
void init(){
inv[1] = 1;
for(int i = 2;i <= N;i++){
inv[i] = (p - p / i) * inv[p % i] % p;
}}
组合数
- 递推
void init(){
for(int i=0;i<4000;i++){
for(int j=0;j<=i;j++){
if(!j) c[i][j]=1;
else c[i][j]=(c[i-1][j]+c[i-1][j-1])%MOD;
}
}}
2.公式 Cba=a!/b!(a−b)!=a!∗b!−1∗(a−b)!−1
即求(b!)逆元和(a-b)!-1的逆元,递推即可
3.卢卡斯公式
int quick_power(int a, int k, int p){
int res = 1;
while (k) {
if (k & 1) {
res = (ll)res * a % p;
}
k >>= 1;
a = (ll)a * a % p;
}
return res;}
int C(int a, int b, int p){
if (b > a) {
return 0;
}
int res = 1;
for (int i = 1, j = a; i <= b; i++, j--) {
res = (ll)res * j % p;
res = (ll)res * quick_power(i, p - 2, p) % p;
}
return res;}int lucas(ll a, ll b, int p)//a个里面调b个{
if (a < p && b < p) {
return C(a, b, p);
}
return (ll)C(a % p, b % p, p) * lucas(a / p, b / p, p) % p;}
矩阵加速
斐波那契求和
#include<bits/stdc++.h>using namespace std;const int N = 3;typedef long long ll;
ll n,m;
ll A[N][N] = // 上述矩阵 A{
{2, 0, -1},
{1, 0, 0},
{0, 1, 0}};
ll S[N] = {2,1,0};void cal(ll A[][N],ll B[][N]){
ll nw[N][N]={0};
for(ll i = 0;i<N;i++){
for(ll j = 0;j<N;j++){
for(ll k = 0;k<N;k++){
nw[i][j] += A[i][k]*B[k][j]%m;
}
}
}
for(ll i = 0;i<N;i++){
for(ll j = 0;j<N;j++){
A[i][j] = nw[i][j]%m;
}
} }void cal(ll A[],ll B[][N]){
ll nw[N] = {0};
for(ll i = 0;i<N;i++){
for(ll j = 0;j<N;j++){
nw[i] += A[j]*B[i][j]%m;
}
}
for(ll i = 0;i<N;i++){
A[i] = nw[i] % m;
}}int main(){
cin>>n>>m;
while(n){
if(n&1){
cal(S,A);
}
cal(A,A);
n>>=1;
}
cout<<((S[2]%m+m)%m)<<endl;
return 0;}
#include<bits/stdc++.h>
using namespace std;
const double eps=1e-7;//其实一般精度*0.1=1e-6就可以了
int n;
double L,R;
double a[15];
//秦九韶算法从里到外逐层计算一次多项式的值
double F(double x)
{
double sum=0;
for(int i=n;i>=0;i--)
sum=sum*x+a[i];
return sum;
}
int main()
{
cin>>n>>L>>R;
for(int i=n;i>=0;i--) cin>>a[i];
while(fabs(L-R)>=eps)
{
double mid=(L+R)/2;
if(F(mid+eps)>F(mid-eps)) L=mid;//舍弃左区间
else R=mid;//舍弃右区间
}
printf("%.5lf",R);
return 0;
}
三.基础算法
RMQ
ll A[N];
ll n;
ll fa[N][30];int main(){
cin>>n;
for(int i = 1;i<=n;i++){
cin>>A[i];
fa[i][0] = A[i];
}
for(int i = 1;i<25;i++){
for(int j = 1;(1<<(i-1))+j<=n;j++){
fa[j][i] = max(fa[j][i-1],fa[j+(1<<(i-1))][i-1]);
}
}
int m;
cin>>m;
while(m--){
ll x,y;
cin>>x>>y;
int t=log2(y-x+1);
cout<<max(fa[x][t],fa[y-(1<<t)+1][t])<<endl;
}
return 0;}
高精度
#include<iostream>
#include<string>
#include<cstring>
#include<cstdio>
using namespace std;
const int N = 1005;
struct bign
{
int len,s[N];
bign() { memset(s,0,sizeof(s)); len=1; }
bign(int num) { *this=num; }
bign(char *num) { *this=num; }
bign operator =(int num)
{
char c[N];
sprintf(c,"%d",num);
*this=c;
return *this;
}
bign operator =(const char *num)
{
len=strlen(num);
for (int i=0;i<len;i++) s[i]=num[len-1-i]-'0';
return *this;
}
string str()
{
string res="";
for (int i=0;i<len;i++) res=(char)(s[i]+'0')+res;
return res;
}
void clean()
{
while (len>1&&!s[len-1]) len--;
}
bign operator +(const bign &b)
{
bign c;
c.len=0;
for (int i=0,g=0;g||i<len||i<b.len;i++)
{
int x=g;
if (i<len) x+=s[i];
if (i<b.len) x+=b.s[i];
c.s[c.len++]=x%10;
g=x/10;
}
return c;
}
bign operator -(const bign &b)
{
bign c;
c.len=0;
int x;
for (int i=0,g=0;i<len;i++)
{
x=s[i]-g;
if (i<b.len) x-=b.s[i];
if (x>=0) g=0;
else{
x+=10;
g=1;
};
c.s[c.len++]=x;
}
c.clean();
return c;
}
bign operator *(const bign &b)
{
bign c;
c.len=len+b.len;
for (int i=0;i<len;i++) for (int j=0;j<b.len;j++) c.s[i+j]+=s[i]*b.s[j];
for (int i=0;i<c.len-1;i++) { c.s[i+1]+=c.s[i]/10; c.s[i]%=10; }
c.clean();
return c;
}
bool operator <(const bign &b)
{
if (len!=b.len) return len<b.len;
for (int i=len-1;i>=0;i--)
if (s[i]!=b.s[i]) return s[i]<b.s[i];
return false;
}
bign operator +=(const bign &b)
{
*this=*this+b;
return *this;
}
bign operator -=(const bign &b)
{
*this=*this-b;
return *this;
}
};
istream& operator >>(istream &in,bign &x)
{
string s;
in>>s;
x=s.c_str();
return in;
}
ostream& operator <<(ostream &out,bign &x)
{
out<<x.str();
return out;
}
int main(){
bign a,b,c;
ios::sync_with_stdio(false);
cin>>a>>b;
// cout<<a<<endl;
// cout<<b<<endl;
c=a+b;
cout<<c<<endl;
return 0;
}
离散化/*去重离散化*/
int tot = 0;
scanf("%d",&n);
over(i,1,n){
scanf("%d",&a[i]);
b[tot++] = a[i];
}
sort(b,b+tot);
int res = unique(b,b+tot)-b;
over(i,1,n)
a[i] = lower_bound(b,b+res,a[i]) - b;
/*主要注意unique的用法,返回的是一个迭代器,而且unique并没有真正删除元素*/
__int128 手写输入输出
__int128 read(){
__int128 res = 0;
int sign = 1;
char ch;
if((ch=getchar())=='-1') sign = -1;
else res = res*10 + ch-'0';
while((ch=getchar())>='0'&&ch<='9'){
res = res*10 + ch-'0';
}
res *= sign;
return res;} void print(__int128 x ){
if(x<0){
x = -x;
printf("-");
}
if(x>9) print(x/10);
putchar(x%10 + '0');}
二分
1答案的最大值,[l, r]划分成[l, mid]和[mid + 1, r]
int bsearch_1(int l, int r){
while (l < r)
{
int mid = l + r >> 1;
if (check(mid)) r = mid;
else l = mid + 1;
}
return l;}
2.答案的最小值,[l, r]划分成[l, mid - 1]和[mid, r]
int bsearch_2(int l, int r){
while (l < r)
{
int mid = l + r + 1 >> 1;
if (check(mid)) l = mid;
else r = mid - 1;
}
return l;}
线性基求第k小
#include<bits/stdc++.h>
#define reg register
using namespace std;
typedef long long ll;
const int MN=60;
ll a[61],tmp[61];
bool flag;
void ins(ll x){
for(reg int i=MN;~i;i--)
if(x&(1ll<<i))
if(!a[i]){a[i]=x;return;}
else x^=a[i];
flag=true;
}
bool check(ll x){
for(reg int i=MN;~i;i--)
if(x&(1ll<<i))
if(!a[i])return false;
else x^=a[i];
return true;
}
ll qmax(ll res=0){
for(reg int i=MN;~i;i--)
res=max(res,res^a[i]);
return res;
}
ll qmin(){
if(flag)return 0;
for(reg int i=0;i<=MN;i++)
if(a[i])return a[i];
}
ll query(ll k){
reg ll res=0;reg int cnt=0;
k-=flag;if(!k)return 0;
for(reg int i=0;i<=MN;i++){
for(int j=i-1;~j;j--)
if(a[i]&(1ll<<j))a[i]^=a[j];
if(a[i])tmp[cnt++]=a[i];
}
if(k>=(1ll<<cnt))return -1;
for(reg int i=0;i<cnt;i++)
if(k&(1ll<<i))res^=tmp[i];
return res;
}
int main(){
int n;ll x;scanf("%d",&n);
for(int i=1;i<=n;i++)scanf("%lld",&x),ins(x);
printf("%lld\n",qmax());
return 0;
}
#include<iostream>
using namespace std;
int A[100001];
int B[100001];
long long map[100001];
int main(){
int n;
cin>>n;
for(int i=1;i<=n;i++){
cin>>A[i];
map[A[i]] = i;
}
for(int i=1;i<=n;i++){
cin>>B[i];
}
for(int i = 1;i<=n;i++){
B[i] = map[B[i]];
A[i] = map[A[i]];
}
int ans[100000];
int len =0;
ans[1] = B[1];
int in = 1;
for(int i = 2;i<=n;i++){
if(B[i]>ans[in]) {
ans[++in] = B[i];
}
else {
int k = lower_bound(ans+1,ans+1+in,B[i])-ans;
ans[k] = B[i];
}
}
cout<<in;
return 0;
}
数位DP
int dp[2000][10],A[N]; long long dfs(int pos ,int limit,int lead,int pre){
long long ans = 0;
if(pos<0) return 1;
if(!limit&&!lead&&dp[pos][pre]!=-1) return dp[pos][pre];
int up = limit?A[pos]:9;
for(int i = 0;i<=up;i++){
if(lead||abs(pre-i)>=2) ans+=dfs(pos-1,limit&&i==up,lead&&i==0,i);
}
if(!limit&&!lead) dp[pos][pre] = ans;
return ans;}
long long slove(long long x){
int pos = 0;
memset(dp,-1,sizeof(dp));
while(x){
A[pos++] = x%10;
x/=10;
}
return dfs(pos-1,1,1,-2);}
背包
01 背包
#include <iostream>
using namespace std;
const int N=1010;
int v[N],w[N],dp[N]={0};
int main()
{
int n,V;
cin >> n >> V;
for(int i=1;i<=n;i++)
{
cin >> v[i] >> w[i];
}
for(int i=1;i<=n;i++)
for(int j=V;j;j--)
{
if(j>=v[i])dp[j]=max(dp[j-v[i]]+w[i],dp[j]);//这里改用了一维的;
}
cout << dp[V];
return 0;
}
完全背包
#include <iostream>
#include <algorithm>
using namespace std;
const int N= 1010;
int n,m;
int dp[N];
int v[N];
int w[N];
int main()
{
cin >> n >> m;
for(int i = 1;i <= n;i++){
cin >> v[i] >> w[i];
}
for(int i = 1;i<=n;i++){
for(int j = v[i];j <= m ;j++){
arr[j] = max(dp[j] , dp[j-v[i]]+w[i]);//每次保留最大的
}
}
cout <<dp[m];
return 0;
}
多重背包(二进制优化)
using namespace std;
int n,m,v,w,s;
int dp[3000];
vector<int>ve;
int main()
{
cin>>n>>m;
for(int i=0;i<n;i++)
{
cin>>v>>w>>s;
ve.clear() ;
for(int q=1;q<s;q<<=1)//将 s 用 二进制的数表示 每次将 q 乘以2,保证是2的整数次方
{
s-=q;
ve.push_back(q);
}
if(s) ve.push_back(s); //如果最后s有剩余,就单独放入;
for(int k=0;k<ve.size();k++)
{
for(int j=m;j>=v*ve[k];j--)//遍历ve中的数据作为01背包,每个数据只会有取和不去的两种选项
{
dp[j]=max(dp[j],dp[j-ve[k]*v]+ve[k]*w);
}
}
}
cout<<dp[m]<<endl;
return 0;
}
混合背包
#include<iostream>
#include<algorithm>
#include<string.h>
#include<vector>
using namespace std;
int n,m,v,w,s;
int dp[3000];
vector<int>ve;
int main()
{
cin>>n>>m;
for(int i=0;i<n;i++)
{
cin>>w>>v>>s;
ve.clear() ;
if(s>0){ //如果是多重的用二进制进行优化
for(int p=1;p<s;p<<=1)
{
ve.push_back(p);
s=s-p;
}
if(s) ve.push_back(s);
}
if(!s)//完全背包
{
for(int j=w;j<=m;j++)
{
dp[j]=max(dp[j],dp[j-w]+v);
}
}
else if(s>0){//多重背包
for(int k=0;k<ve.size();k++)
{
for(int j=m;j>=w*ve[k];j--)
dp[j]=max(dp[j],dp[j-w*ve[k]]+ve[k]*v);
}
}
else{//01背包
for(int j=m;j>=w;j--)
{
dp[j]=max(dp[j],dp[j-w]+v);
}
}
}
cout<<dp[m]<<endl;
return 0;
}
二维费用的背包问题
#include<iostream>
#include<algorithm>
#include<string.h>
using namespace std;
int n,V,M;
int dp[1500][1500];
int v,m,w;
int main()
{
cin>>n>>V>>M;
for(int i=0;i<n;i++)
{
cin>>v>>w>>m;
for(int j=V;j>=v;j--)//两个循环分别遍历体积的质量遍历的规则和一维的一样
{
for(int k=M;k>=w;k--)
{
dp[j][k]=max(dp[j][k],dp[j-v][k-w]+m);
}
}
}
cout<<dp[V][M]<<endl;
return 0;
}
背包问题求方案数
#include<string.h>
#include<iostream>
#include<algorithm>
using namespace std;
int dp[1090];
int flag[1090];
int n,v,V,m;
const int mod=1e9+7;
int main()
{
cin>>n>>V;
flag[0]=1;
for(int i=0;i<n;i++)
{
cin>>v>>m;
for(int j=V;j>=v;j--)
{
int s=0;
int t=max(dp[j],dp[j-v]+m);//还和之前的一样遍历只是中间需要记录路径数所以不能直接赋值
if(t==dp[j]) s+=flag[j];//当t=dp[j]时s加上flag【j】
if(t==dp[j-v]+m) s=s+flag[j-v];//当t=dp[j-v]+m时s加上flag[j-v]
flag[j]=s%mod;//注意取mod 只是因为 有可能两种不同的路径取出来的最大值是相同的
dp[j]=t;
}
}
int maxn=-1;
int sum=0;
for(int i=0;i<=V;i++) maxn=max(maxn,dp[i]);//遍历最大值
for(int i=0;i<=V;i++)
{
if(dp[i]==maxn)
{
sum=(sum+flag[i])%mod;//路径相加
}
}
cout<<sum<<endl;
return 0;
}
//强连通分量 kosaraju
// 洛谷 P2341
#include<bits/stdc++.h>
using namespace std;
const int N = 1e6+7; int n,m;
struct edge{
int to;
int next;
}e[N],e_[N];
int w[N];
int head[N],ecnt = 0;
int head_[N],ecnt_ = 0;
int f[N]; //表示第i个点是属于f【i】的强连通分量
int order[N];
int vis[N];
int A[N],B[N];
long long ans;
long long dp[N]={0};
int t = 0;
void add(int u,int v){
e[++ecnt].to = v;
e[ecnt].next = head[u];
head[u] = ecnt;
}
void add_(int u,int v){
e_[++ecnt_].to = v;
e_[ecnt_].next = head_[u];
head_[u] = ecnt_;
}
void dfs1(int x){
vis[x] =1;
for(int i = head[x];i;i = e[i].next){
int u = e[i].to;
if(!vis[u])dfs1(u);
}
order[++t] = x;
}
void dfs2(int x,int y){
vis[x]= 1 ;
for(int i = head_[x];i;i = e_[i].next){
int u = e_[i].to;
if(!vis[u]){
dfs2(u,y);
}
}f[x] = y;
}
void kosaraju(){
//先从前往后遍历图,求出order数组
//再跟据order从后往前遍历反图,记录f[i](每个点隶属的强连通分量)
for(int i = 1;i<=n;i++) {
if(!vis[i])dfs1(i);
}
memset(vis,0,sizeof(vis));
for(int i = t;i>=1;i--){
if(!vis[order[i]])
dfs2(order[i],order[i]);
}
memset(vis,0,sizeof(vis));
}
void build(){
ecnt = 1;
memset(head,0,sizeof(head));
for(int i =0 ;i<m;i++){
int a = A[i],b = B[i];
if(f[A[i]]!=f[B[i]]) add(f[A[i]],f[B[i]]);
else {
if(!vis[a]&&f[a]!=a) w[f[a]] += w[a];
if(!vis[b]&&f[a]!=b) w[f[a]] += w[b];
vis[a] = vis[b] = 1;
}
}
}
void dfs3(int x){
if(dp[x]) return ;
for(int i = head[x];i;i = e[i].next){
if(!dp[e[i].to]) dfs3(e[i].to);
dp[x] = max(dp[x],dp[e[i].to]);
}
dp[x] += w[x];
}
int dag(){
ans = -INT_MAX;
for(int i = 1;i<=n;i++){
if(!dp[f[i]]) dfs3(f[i]),ans = max(ans,dp[f[i]]);
}
}
int main(){
cin>>n>>m;
for(int i = 1;i<=n;i++) cin>>w[i];
for(int i = 0;i<m;i++){
int a,b;
scanf("%d %d",&a,&b);
A[i] = a;
B[i] = b;
add(a,b);
add_(b,a);
}
kosaraju();
build();
dag();
cout<<ans<<endl;
return 0;
}
2 - sat
#include<bits/stdc++.h>
using namespace std;
const int N = 3e6+7;
struct node{
int to,next;
}e[N],e2[N];
int head[N],head2[N],vis[N],n,m,ans=0,A[N],B[N],ecnt=0,ecnt2=0,f[N],t=0,ord[N]={0};
int ru[N],chu[N];
void add(int u,int v){
e[++ecnt].to = v;e[ecnt].next = head[u];head[u] = ecnt;
}
void add2(int u,int v){
e2[++ecnt2].to = v;e2[ecnt2].next = head2[u];head2[u] = ecnt2;
}
void dfs1(int x){
vis[x]=1;
for(int i = head[x];i;i=e[i].next) {
int u = e[i].to;
if(!vis[u]) dfs1(u);
}
ord[++t] = x;
}
int cnt = 0;
void dfs2(int x){
f[x] = cnt;
vis[x]=1;
for(int i = head2[x];i;i=e2[i].next){
int u = e2[i].to;
if(!vis[u])dfs2(u);
}
}
void kosaraju(){
for(int i = 1;i<=2*n;i++) if(!vis[i]) dfs1(i);
memset(vis,0,sizeof(vis));
for(int i = 2*n;i>=1;i--) if(!vis[ord[i]]) cnt++,dfs2(ord[i]);
memset(vis,0,sizeof(vis));
}
int main(){
cin>>n>>m;
for(int i = 0;i<m;i++){
int x,f1,y,f2;
scanf("%d%d%d%d",&x,&f1,&y,&f2);
add(x+n*(f1&1),y+n*(f2^1));
add(y+n*(f2&1),x+n*(f1^1));
add2(y+n*(f2^1),x+n*(f1&1));
add2(x+n*(f1^1),y+n*(f2&1));
}
kosaraju();
for(int i = 1;i<=n;i++){
if(f[i]==f[i+n]) {
cout<<"IMPOSSIBLE"<<endl;
return 0;
}
}
cout<<"POSSIBLE"<<endl;
for(int i=1;i<=n;i++) {
cout<<(f[i]>f[i+n])<<" ";
}
return 0;
}
#include<bits/stdc++.h>
using namespace std;
const int N = 1e6+7;
int n;
struct edge{
int to,next,w;
}e[N];
int vis[N];
int cnt[N];
int ecnt = 0,head[N];
void add(int u,int v,int w){
e[++ecnt].to=v;
e[ecnt].w=w;
e[ecnt].next=head[u];
head[u] = ecnt;
}
int dist[N];
bool spfa(){
dist[0] = 0;
queue<int> q;
q.push(0);
vis[0] = 1;
cnt[0]++;
while(!q.empty()){
int k = q.front();
q.pop();
vis[k] = 0;
for(int i = head[k];i;i=e[i].next){
int to = e[i].to;
int w = e[i].w;
if( dist[to] < dist[k] + w){
dist[to] = dist[k]+w;
if(!vis[to]){
vis[to] = 1;
if(cnt[to]>n) return 0;
cnt[to]++;
q.push(to);
}
}
}
}
return 1;
}
int main(){
int m;
cin>>n>>m;
for(int i=0;i<m;i++){
int a,b,c;
cin>>a>>b>>c;
add(a,b,-c);
}
for(int i = 1;i <=n;i++) add(0,i,0),dist[i]=-10000;
if(spfa()==0){
cout<<"NO"<<endl;
}
else
for(int i = 1;i<=n;i++) cout<<dist[i]<<" ";
return 0;
}
#include<bits/stdc++.h>
using namespace std;
const int N = 6e3+7;
typedef long long ll;
int inf = 1e9;
struct node{
int dis,id;
bool operator<(const node a)const{
return dis>a.dis;
}
};
struct edge{
int to,next,w;
}e[100001];
ll head[N],ecnt=0,vis[N],dp[N],check_cir[N],n,m,dis[N];
void add(int u,int v,int w){
e[++ecnt].w = w;
e[ecnt].to = v;
e[ecnt].next = head[u];
head[u] = ecnt;
}
void dijkstra(int s){
priority_queue<node> q;
memset(vis,0,sizeof(vis));
for(int i = 0;i<=n;i++) dis[i] = inf;
q.push({0,s});
dis[s] = 0;
while(!q.empty()){
int u = q.top().id;
ll d = q.top().dis;
q.pop();
if(vis[u]) continue;
vis[u] = 1;
for(int i = head[u]; i ;i = e[i].next){
int to = e[i].to,w = e[i].w;
if(dis[to]>w+dis[u]){
dis[to] = w + dis[u];
if(!vis[to])
q.push({dis[to],to});
}
}
}
}
bool spfa(int v){
vis[v] = 1;
queue<int> q;
for(int i = 0;i<=n;i++) dp[i] = inf;
dp[v] = 0;
q.push(v);
while(!q.empty()){
int u = q.front();
vis[u] = 0;
q.pop();
for(int i = head[u];i;i=e[i].next){
int to = e[i].to,w = e[i].w;
if(dp[u]+w<dp[to]){
dp[to] = dp[u]+w;
if(!vis[to]){
vis[to] = 1;
q.push(to);
check_cir[to]++;
if(check_cir[to]>n) return 0;
}
}
}
}
return 1;
}
int main(){
ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr);
cin>>n>>m;
for(int i = 0;i<m;i++){
int x,y,w;
cin>>x>>y>>w;
add(x,y,w);
}
for(int i = 1;i<=n;i++){
add(0,i,0);
}
if(!spfa(0)) {
cout<<-1<<endl;
return 0;
}
else {
for(int i = 1;i<=n;i++){
for(int j = head[i];j;j=e[j].next){
int to = e[j].to;
e[j].w += dp[i] - dp[to];
}
} // 修改边权
for(int i = 1;i<=n;i++){
dijkstra(i);
ll ans = 0;
for(ll j = 1;j<=n;j++){
if(dis[j] == inf){
ans += j*inf;
}
else ans += j * (dis[j] + dp[j] - dp[i]);
}
cout<<ans<<endl;
}
}
return 0;
}
(最大独立集=n-最小点覆盖=n-最大边匹配)
#include<bits/stdc++.h>
using namespace std;
const int N = 1e6+7;
struct edge{
int to,next;
}e[N];
int ecnt,head[N],n,k;
void add(int u,int v){
e[++ecnt].to = v;
e[ecnt].next = head[u];
head[u] = ecnt;
}
int G[1000][1000],ans;
int dir[4][2] = {1,0,0,1,0,-1,-1,0};
int math[N],vis[21000];
bool dfs(int v){
for(int i = head[v];i;i = e[i].next){
int to = e[i].to;
if(!vis[to]){
vis[to] = 1;
if(!math[to]||dfs(math[to])) {
math[to] = v;
return 1;
}
}
}
return 0;
}
int main(){
cin>>n>>k;
for(int i = 0;i<k;i++){
int x,y;
cin>>x>>y;
G[x][y] = 1;
}
for(int i = 1;i<=n;i++){
for(int j = 1;j<=n;j++){
if((i+j)&1||G[i][j]) continue;
for(int k = 0;k<4;k++){
int x = dir[k][0] + i;
int y = dir[k][1] + j;
if(x>=1&&y>=1&&x<=n&&y<=n&&G[x][y]==0){
add((i-1)*n+j,(x-1)*n+y);
}
}
}
}
for(int i = 1;i<=n;i++){
for(int j = 1;j<=n;j++){
if((i+j)&1) continue;
memset(vis,0,sizeof(vis));
if(dfs((i-1)*n+j)) ans++;
}
}
cout<<ans<<endl;
return 0;
}
最大流问题
EK算法
#include<bits/stdc++.h>
using namespace std;
const int N = 1e6+7;
typedef long long ll;
int n,m,x;
struct edge{
int from,to,next,w;
}e[N];
int head[N],ecnt=0,A[N],fa[N];
void add(int u,int v,int w){
e[ecnt] = {u,v,head[u],w};
head[u] = ecnt++;
}
bool bfs(){
queue<int> q;
q.push(1);
for(int i = 0;i<=n;i++) A[i] = 0;
A[1] = 0x3f3f3f3f;
while(!q.empty()){
int u = q.front();
q.pop();
for(int i = head[u];i!=-1;i = e[i].next){
int to = e[i].to , w = e[i].w;
if(!A[to]&&e[i].w){
fa[to] = i;
A[to] = min(A[u],w);
q.push(to);
}
}
if(A[n]) return 1;
}
return 0;
}
ll EK(){
ll ans = 0;
while(bfs()){
for(int i = n;i!=1;i = e[fa[i]].from){
e[fa[i]].w -= A[n];
e[fa[i]^1].w += A[n];
}
ans += A[n];
}
return ans;
}
int main(){
ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr);
cin>>n>>m>>x;
for(int i = 0;i<4*m;i++){
head[i] = -1;
}
for(int i = 0;i<m;i++){
int a,b,c;
cin>>a>>b>>c;
add(a,b,c);
add(b,a,0);
}
ll ans = EK();
if(ans == 0) cout<<"Orz Ni Jinan Saint Cow!\n";
else {
cout<<ans<<" ";
ans = ceil(x*1.0/ans);
cout<<ans<<"\n";
}
return 0;
}
Dinic算法
#include<bits/stdc++.h>
using namespace std;
const int N = 1e6+7;
typedef long long ll;
#define int long long
const int inf = 0x3f3f3f3f;
int n,m,s,t;
struct edge{
int to,next,now,w;
}e[N];
int head[N],ecnt,d[N],vis[N],cur[N];
void add(int u,int v,int w){
e[ecnt] = {v,head[u],0,w};
head[u] = ecnt++;
}
bool bfs(int s,int t){
for(int i = 0;i<=n;i++) d[i] = vis[i] = 0;
queue<int> q;
q.push(s);
vis[s] = 1;
while(!q.empty()){
int u = q.front();
q.pop();
for(int i = head[u];~i;i = e[i].next){
int to = e[i].to,now = e[i].now,w = e[i].w;
if(!vis[to]&&now < w){
vis[to] = 1;
d[to] = d[u] + 1;
q.push(to);
if(to == t) return 1;
}
}
}
return vis[t];
}
ll dfs(int u,int t,int imp){
if(u == t || !imp) return imp;
ll res = 0;
for(int &i = cur[u];~i;i=e[i].next){
int to = e[i].to;
int now = e[i].now;
if(d[u]+1!=d[to]) continue;
int f = dfs(to,t,min(imp,e[i].w-now)) ;
if(f==0) continue;
e[i].now += f;
e[i^1].now -= f;
res += f;
imp -= f;
if(!imp) break;
}
return res;
}
ll Dinic(){
ll flow = 0;
while(bfs(s,t)){
for(int i = 0;i<=m;i++){
cur[i] = head[i];
}
flow += dfs(s,t,inf);
}
return flow;
}
signed main(){
ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr);
cin>>n>>m>>s>>t;
for(int i = 0;i<=m;i++){
head[i] = -1;
}
for(int i = 0;i<m;i++){
int a,b,w;
cin>>a>>b>>w;
add(a,b,w);
add(b,a,0);
}
cout<<Dinic()<<endl;
return 0;
}
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll N=505;
const ll inf=1e18;
ll n,m,G[N][N],matched[N];
ll slack[N],pre[N],ex[N],ey[N];//ex,ey顶标
bool visx[N],visy[N];
ll A[N],P[N],C[N],B[N];
pair<ll,ll> pi[N];
void dfs(ll u)
{
ll x,y=0,yy=0,delta;
memset(pre,0,sizeof(pre));
for(ll i=1;i<=n;i++)slack[i]=inf;
matched[y]=u;
while(1)
{
x=matched[y];delta=inf;visy[y]=1;
for(ll i=1;i<=n;i++)
{
if(visy[i])continue;
if(slack[i]>ex[x]+ey[i]-G[x][i])
{
slack[i]=ex[x]+ey[i]-G[x][i];
pre[i]=y;
}
if(slack[i]<delta){delta=slack[i];yy=i;}
}
for(ll i=0;i<=n;i++)
{
if(visy[i])ex[matched[i]]-=delta,ey[i]+=delta;
else slack[i]-=delta;
}
y=yy;
if(matched[y]==-1)break;
}
while(y){matched[y]=matched[pre[y]];y=pre[y];}
}
ll KM()
{
memset(matched,-1,sizeof(matched));
memset(ex,0,sizeof(ex));
memset(ey,0,sizeof(ey));
for(ll i=1;i<=n;i++)
{
memset(visy,0,sizeof(visy));
dfs(i);
}
ll res=0;
for(ll i=1;i<=n;i++)
if(matched[i]!=-1)res+=G[matched[i]][i];
return res;
}
int main()
{
ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr);
cin>>n>>m;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
G[i][j]=-inf;
for(int i = 1;i<=m;i++){
ll a,b,c;
cin>>a>>b>>c;
G[a][b] = c;
}
printf("%lld\n",KM());
for(int i = 1;i<=n;i++){
printf("%lld ",matched[i]);
}
return 0;
}
// n 存的点的个数 ,KM()表示最大权匹配,mathched表示匹配结果
(1) 存在欧拉路径的充分必要条件: 度数为奇数的点只能是0或者2个(0个为欧拉回路的情况)
(2) 存在欧拉回路的充分必要条件: 度数为奇数的点只能有0个
#include<bits/stdc++.h>
using namespace std;
const int N = 1e6+7;
int n,m,ver,use[N],din[N],dout[N],head[N],ecnt,dfn[N],low[N];
struct edge{
int next,to;
}e[N];
void add(int u,int v){
e[ecnt].to = v;
e[ecnt].next = head[u];
head[u] = ecnt++;
}
vector<int> ans;
void dfs(int u){
for(int &i = head[u];~i;){
if(use[i]) {
i = e[i].next;
continue;
}
use[i] = 1;
if(ver) use[i^1] = 1;
int t;
if(ver) {
t = i/2+1;
if(i&1) t = -t;
}
else t = i+1;
int to = e[i].to;
i = e[i].next;
dfs(to);
ans.push_back(t);
}
}
int main(){
cin>>ver>>n>>m;
if(ver==2) ver = 0;
memset(head,-1,sizeof head);
for(int i = 0;i<m;i++){
int a,b;
cin>>a>>b;
add(a,b);
if(ver) add(b,a);
din[b]++;dout[a]++;
}
if(ver==1){
for(int i = 1;i<=n; i++){
if(din[i]+dout[i] &1){
cout<<"NO"<<endl;
return 0;
}
}
}
else for(int i = 1;i<=n;i++){
if(din[i] != dout[i]){
cout<<"NO"<<endl;
return 0;
}
}
for(int i = 1;i<=n;i++){
if(~head[i]){
dfs(i);
break;
}
}
if(ans.size()<m) cout<<"NO"<<endl;
else{
cout<<"YES"<<endl;
for(int i = (int)ans.size()-1;i>=0;i--){
cout<<ans[i]<<" ";
}
}
return 0;
}