一题多解
目录
二维DP转图论
dp
#include <bits/stdc++.h>
constexpr int inf = 1E9;
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
int f, v;
std::cin >> f >> v;
std::vector a(f, std::vector<int>(v));
for (int i = 0; i < f; ++i) {
for (int j = 0; j < v; ++j) {
std::cin >> a[i][j];
}
}
std::vector dp(f + 1, std::vector<int>(v + 1, -inf));
dp[0].assign(v + 1, 0);
for (int i = 0; i < f; ++i) {
for (int j = i; j < v; ++j) {
dp[i + 1][j + 1] = std::max(dp[i + 1][j], dp[i][j] + a[i][j]);
}
}
std::cout << dp[f].back() << "\n";
std::vector<int> ans(f);
for (int i = f, j = v; i >= 0; --i) {
while (j > 0 && dp[i][j] == dp[i][j - 1]) {
--j;
}
ans[i - 1] = j--;
}
for (int x = 0; x < ans.size(); ++x) {
std::cout << ans[x] << " \n"[x + 1 == ans.size()];
}
}
dijkstra / spfa最长路
//楼下全是dp,那么来个最长路做法
//可以将这个看成一个以花为横,瓶为纵的表格从下向上找一条路径,上一排的位置必须小于下一排
//那么我们就可以连边去跑最长路了
//同时我们注意到需要记录路径
//那么这里就选dij好了(因为其他的不会记路径啊)
#include<iostream>
#include<cstdio>
#include<queue>
#include<cstring>
#pragma GCC optimize(3)
#define re register
#define maxn 10001
#define maxw 800000
#define inf -99999999
using namespace std;
struct node
{
int v,w,nxt;
}e[maxw];
int f,v,ans,num=1,end;
int head[maxn],d[maxn],r[maxn];
int a[101][101];
typedef pair<int,int> pii;
priority_queue<pii,vector<pii>,less<pii> > q;
inline int read()
{
char c=getchar();
int x=0;
int r=1;
while(c<'0'||c>'9')
{
if(c=='-') r=-1;
c=getchar();
}
while(c>='0'&&c<='9')
{
x=x*10+c-48;
c=getchar();
}
return r*x;
}
inline void add_edge(int x,int y,int z)
{
e[num].v=y;
e[num].w=z;
e[num].nxt=head[x];
head[x]=num++;
}
inline void dijkstra(int s)
{
for(re int i=1;i<=f*v;i++)
d[i]=inf;
d[s]=0;
q.push(make_pair(d[s],s));
while(q.size())
{
pii mid=q.top();
q.pop();
int k=mid.second;
for(re int i=head[k];i;i=e[i].nxt)
if(d[e[i].v]<d[k]+e[i].w)
{
d[e[i].v]=d[k]+e[i].w;
q.push(make_pair(d[e[i].v],e[i].v));//很常规的松弛操作
r[e[i].v]=k;//存一下前驱结点,用来找路径
}
}
}
void dfs(int i)
{
if(i!=0) dfs(r[i]);
if(i!=0) cout<<i%v<<" ";//dfs找出路径,再将点还原成二维
}
int main()
{
f=read();
v=read();
for(re int i=1;i<=f;i++)
for(re int j=1;j<=v;j++)
a[i][j]=read();
for(re int i=1;i<=v;i++)
add_edge(0,i,a[1][i]);//我们把0作为起点,把第一列的所有点与0相连
for(re int i=2;i<=f;i++)
for(re int k=1;k<=v;k++)
for(re int j=k+1;j<=v;j++)
add_edge((i-2)*v+k,(i-1)*v+j,a[i][j]);//把点的坐标压成一维
//连边,需要注意的是上一行点的横坐标要小于下一行的
dijkstra(0);
ans=inf;
for(re int i=1;i<=v;i++)
if(ans<d[(f-1)*v+i])//从最后一行找最长路
{
ans=d[(f-1)*v+i];
end=(f-1)*v+i;
}
cout<<ans<<endl;
dfs(r[end]);
end%=v;
if(end==0) end=v;
cout<<end<<endl;
return 0;
}
最小费用最大流
#include<bits/stdc++.h>
using namespace std;
struct Edge
{
int to,nxt,flow,cost;
}edge[500005];
int fir[100005],cnt=1;
void add(int u,int v,int w,int c)
{
edge[++cnt]=(Edge){v,fir[u],w,-c},fir[u]=cnt;
edge[++cnt]=(Edge){u,fir[v],0,c},fir[v]=cnt;
}
int dis[100005],vis[100005];
int s,t;
int n,m;
bool spfa()
{
memset(dis,0x3f,sizeof(dis));
memset(vis,0,sizeof(vis));
queue<int>q;
q.push(s);
dis[s]=0;
while(!q.empty())
{
int u=q.front();
q.pop();
vis[u]=0;
for(int i=fir[u];i;i=edge[i].nxt)
{
int v=edge[i].to;
if(dis[v]>dis[u]+edge[i].cost&&edge[i].flow)
{
dis[v]=dis[u]+edge[i].cost;
if(!vis[v])q.push(v),vis[v]=1;
}
}
}
return dis[t]<0x3f3f3f3f;
}
int MC,MF;
int dfs(int u,int flow)
{
if(u==t)
{
MF+=flow;
vis[u]=1;
return flow;
}
int used=0;
vis[u]=1;
for(int i=fir[u];i;i=edge[i].nxt)
{
int v=edge[i].to;
if((v==t||!vis[v])&&edge[i].flow&&dis[v]==dis[u]+edge[i].cost)
{
int mi=dfs(v,min(flow-used,edge[i].flow));
if(mi)
{
edge[i].flow-=mi;
edge[i^1].flow+=mi;
used+=mi;
MC+=mi*edge[i].cost;
}
if(used==flow)return used;
}
}
return used;
}
void MCMF()
{
while(spfa())
{
vis[t]=1;
while(vis[t])memset(vis,0,sizeof(vis)),dfs(s,1);
}
}
int main()
{
s=0,t=50000;
int s2=50001;
add(s,s2,1,0);
scanf("%d%d",&n,&m);
int sum=n*m;
for(int i=1;i<=n;++i)
{
for(int j=1;j<=m;++j)
{
int k;
scanf("%d",&k);
add((i-1)*m+j,(i-1)*m+j+sum,1,k);
}
}
for(int i=1;i<n;++i)
{
for(int j=1;j<m;++j)
{
for(int k=j+1;k<=m;++k)
{
add((i-1)*m+j+sum,i*m+k,1,0);
}
}
}
for(int i=1;i<=m;++i)
{
add(s2,i,1,0);
add((n-1)*m+i+sum,t,1,0);
}
MCMF();
printf("%d\n",-MC);
for(int i=1;i<=n;++i)
{
for(int j=1;j<=m;++j)
{
for(int k=fir[(i-1)*m+j];k;k=edge[k].nxt)
{
int v=edge[k].to;
if(v-((i-1)*m+j)==sum&&edge[k].flow==0)
{
printf("%d ",j);
}
}
}
}
}
P1073 [NOIP 2009 提高组] 最优贸易
SCC
#include <bits/stdc++.h>
using i64 = long long;
struct SCC {
int n;
std::vector<std::vector<int>> adj;
std::vector<int> stk;
std::vector<int> dfn, low, bel;
int cur, cnt;
SCC() {}
SCC(int n) {
init(n);
}
void init(int n) {
this->n = n;
adj.assign(n, {});
dfn.assign(n, -1);
low.resize(n);
bel.assign(n, -1);
stk.clear();
cur = cnt = 0;
}
void addEdge(int u, int v) {
adj[u].push_back(v);
}
void dfs(int x) {
dfn[x] = low[x] = cur++;
stk.push_back(x);
for (auto y : adj[x]) {
if (dfn[y] == -1) {
dfs(y);
low[x] = std::min(low[x], low[y]);
} else if (bel[y] == -1) {
low[x] = std::min(low[x], dfn[y]);
}
}
if (dfn[x] == low[x]) {
int y;
do {
y = stk.back();
bel[y] = cnt;
stk.pop_back();
} while (y != x);
cnt++;
}
}
std::vector<int> work() {
// for (int i = 0; i < n; i++) {
// if (dfn[i] == -1) {
// dfs(i);
// }
// }
dfs(0);
return bel;
}
};
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
int n, m;
std::cin >> n >> m;
std::vector<int> a(n);
for (int i = 0; i < n; ++i) {
std::cin >> a[i];
}
SCC g(n);
for (int i = 0, u, v, t; i < m; ++i) {
std::cin >> u >> v >> t;
--u, --v;
g.addEdge(u, v);
if (t == 2) {
g.addEdge(v, u);
}
}
g.work();
int N = g.cnt;
constexpr int inf = 1E9;
std::vector<int> f0(N, inf), f1(N);
for (int i = 0; i < n; ++i) {
int j = g.bel[i];
if (j == -1) {
continue;
}
f0[j] = std::min(f0[j], a[i]);
f1[j] = std::max(f1[j], a[i]);
}
std::vector<std::vector<int>> adj(N);
std::vector<int> d(N);
for (int i = 0; i < n; ++i) {
for (auto v : g.adj[i]) {
int x = g.bel[i], y = g.bel[v];
if (x == y || x == -1 || y == -1) {
continue;
}
adj[x].push_back(y);
++d[y];
}
}
std::vector<int> dp(N);
std::queue<int> q;
q.push(g.bel[0]);
int ans = 0;
while (!q.empty()) {
auto u = q.front();
q.pop();
dp[u] = std::max(dp[u], f1[u] - f0[u]);
for (auto v : adj[u]) {
f0[v] = std::min(f0[v], f0[u]);
dp[v] = std::max(dp[u], dp[v]);
if (--d[v] == 0) {
q.push(v);
}
}
}
std::cout << dp[g.bel[n - 1]] << "\n";
}
分层图

#include <bits/stdc++.h>
using i64 = long long;
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
int n, m;
std::cin >> n >> m;
std::vector<int> a(n);
for (int i = 0; i < n; ++i) {
std::cin >> a[i];
}
std::vector<std::vector<std::pair<int, int>>> adj(3 * n);
auto addEdge = [&](int u, int v) {
adj[u].push_back({v, 0});
adj[u + n].push_back({v + n, 0});
adj[u + 2 * n].push_back({v + 2 * n, 0});
};
for (int i = 0, u, v, t; i < m; ++i) {
std::cin >> u >> v >> t;
--u, --v;
addEdge(u, v);
if (t == 2) {
addEdge(v, u);
}
}
for (int u = 0; u < n; ++u) {
adj[u].push_back({u + n, -a[u]});
adj[u + n].push_back({u + 2 * n, a[u]});
}
constexpr int inf = 1E9;
std::vector<int> dist(3 * n, -inf);
auto spfa = [&]() -> void {
std::vector<bool> st(3 * n);
std::queue<int> q;
q.push(0);
st[0] = true;
dist[0] = 0;
while (!q.empty()) {
auto u = q.front();
q.pop();
st[u] = false;
for (auto [v, w] : adj[u]) {
if (dist[v] >= dist[u] + w) {
continue;
}
dist[v] = dist[u] + w;
if (!st[v]) {
st[v] = true;
q.push(v);
}
}
}
};
spfa();
std::cout << std::max(dist.back(), 0) << "\n";
}s
反图
后面最大 - 前面最小
两次SPFA
#include <bits/stdc++.h>
using i64 = long long;
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
int n, m;
std::cin >> n >> m;
std::vector<int> a(n);
for (int i = 0; i < n; ++i) {
std::cin >> a[i];
}
std::vector<std::vector<int>> g(n), rg(n);
for (int i = 0, u, v, t; i < m; ++i) {
std::cin >> u >> v >> t;
--u, --v;
g[u].push_back(v);
rg[v].push_back(u);
if (t == 2) {
g[v].push_back(u);
rg[u].push_back(v);
}
}
constexpr int inf = 1E9;
std::vector<int> mn(n, inf);
{
std::queue<int> q;
std::vector<bool> inq(n, false);
mn[0] = a[0];
q.push(0);
inq[0] = true;
while (!q.empty()) {
int u = q.front();
q.pop();
inq[u] = false;
for (int v : g[u]) {
if (mn[v] > std::min(mn[u], a[v])) {
mn[v] = std::min(mn[u], a[v]);
if (!inq[v]) {
inq[v] = true;
q.push(v);
}
}
}
}
}
std::vector<int> mx(n, -inf);
{
std::queue<int> q;
std::vector<bool> inq(n, false);
mx[n - 1] = a[n - 1];
q.push(n - 1);
inq[n - 1] = true;
while (!q.empty()) {
int u = q.front();
q.pop();
inq[u] = false;
for (int v : rg[u]) {
if (mx[v] < std::max(mx[u], a[v])) {
mx[v] = std::max(mx[u], a[v]);
if (!inq[v]) {
inq[v] = true;
q.push(v);
}
}
}
}
}
int ans = 0;
for (int i = 0; i < n; ++i) {
if (mn[i] == inf || mx[i] == -inf) {
continue;
}
ans = std::max(ans, mx[i] - mn[i]);
}
std::cout << ans << '\n';
return 0;
}
XOR 问题
数组A全部xor 一个数,使得最大值最小
问题
Trie
#include <bits/stdc++.h>
using i64 = long long;
constexpr int N = 1E7;
int tot;
int trie[N][2];
int newNode() {
++tot;
trie[tot][0] = trie[tot][1] = 0;
return tot;
}
void insert(int x) {
int p = 1;
for (int i = 30; i >= 0; --i) {
int u = x >> i & 1;
if (!trie[p][u]) {
trie[p][u] = newNode();
}
p = trie[p][u];
}
}
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
int n;
std::cin >> n;
std::vector<int> a(n);
for (int i = 0; i < n; ++i) {
std::cin >> a[i];
}
tot = 0;
newNode();
for (int x : a) {
insert(x);
}
auto dfs = [&](this auto &&self, int p, int k) -> int {
if (p == 0) {
return 0;
}
if (trie[p][0] && trie[p][1]) {
return std::min(self(trie[p][0], k - 1), self(trie[p][1], k - 1)) | 1 << k;
}
return self(std::max(trie[p][0], trie[p][1]), k - 1);
};
std::cout << dfs(1, 30);
}
sort + partition_point
#include <bits/stdc++.h>
using i64 = long long;
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
int N;
std::cin >> N;
std::vector<int> a(N);
for (int i = 0; i < N; i++) {
std::cin >> a[i];
}
std::sort(a.begin(), a.end());
auto solve = [&](auto solve, int l, int r, int k) {
if (k == 0) return 0;
int m = std::partition_point(a.begin() + l, a.begin() + r, [&](int x) { return ~x >> (k - 1) & 1; }) - a.begin();
if (l == m || m == r) return solve(solve, l, r, k - 1);
return std::min(solve(solve, l, m, k - 1), solve(solve, m, r, k - 1)) | 1 << (k - 1);
};
std::cout << solve(solve, 0, N, 30) << "\n";
return 0;
}
数组中 $ A_i + A_j = C$ 的个数
二分
#include <bits/stdc++.h>
using i64 = long long;
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
int n, c;
std::cin >> n >> c;
std::vector<int> a(n);
for (int i = 0; i < n; ++i) {
std::cin >> a[i];
}
std::sort(a.begin(), a.end());
i64 ans = 0;
for (int i = 0; i < n; ++i) {
int x = a[i] - c;
ans += std::upper_bound(a.begin(), a.end(), x) - std::lower_bound(a.begin(), a.end(), x);
}
std::cout << ans << "\n";
}
双指针
#include <bits/stdc++.h>
using i64 = long long;
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
int n, c;
std::cin >> n >> c;
std::vector<int> a(n);
for (int i = 0; i < n; ++i) {
std::cin >> a[i];
}
std::sort(a.begin(), a.end());
i64 ans = 0;
for (int i = 0, l = 0, r = 0; i < n; ++i) {
int x = a[i] - c;
while (a[l] < x) {
++l;
}
while (a[r] <= x) {
++r;
}
ans += r - l;
}
std::cout << ans << "\n";
}
hash表
#include <bits/stdc++.h>
using i64 = long long;
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
i64 n, c;
std::cin >> n >> c;
std::vector<i64> v(n);
for (int i = 0; i < n; ++i) {
std::cin >> v[i];
}
std::unordered_map<i64, int> h;
i64 re = 0;
for (i64 x : v) {
re += h[x - c] + h[c + x];
++h[x];
}
std::cout << re;
return 0; // 结束了罪恶的一生!
}
仓库选址
数轴上n个人的坐标,问走的一起的总路程最小是多少?
#include <bits/stdc++.h>
using i64 = long long;
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
int n;
std::cin >> n;
std::vector<int> a(n);
for (int i = 0; i < n; ++i) {
std::cin >> a[i];
}
int m = n / 2;
std::sort(a.begin(), a.end());
i64 ans = 0;
for (int x : a) {
ans += std::abs(x - a[m]);
}
std::cout << ans << "\n";
}
#include <bits/stdc++.h>
using i64 = long long;
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
int n;
std::cin >> n;
std::vector<int> a(n);
for (int i = 0; i < n; ++i) {
std::cin >> a[i];
}
std::sort(a.begin(), a.end());
i64 ans = 0;
for (int i = 0; i < n; ++i) {
ans += a[i] - a[i / 2];
}
std::cout << ans << "\n";
}
#include <bits/stdc++.h>
using i64 = long long;
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
int n;
std::cin >> n;
std::vector<int> a(n);
for (int i = 0; i < n; ++i) {
std::cin >> a[i];
}
int m = n / 2;
std::nth_element(a.begin(), a.begin() + m, a.end());
i64 ans = 0;
for (int x : a) {
ans += std::abs(x - a[m]);
}
std::cout << ans << "\n";
}
#include <bits/stdc++.h>
using i64 = long long;
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
int n;
std::cin >> n;
constexpr int N = 4E4 + 5;
std::vector<int> cnt(N);
for (int i = 0, x; i < n; ++i) {
std::cin >> x;
++cnt[x];
}
i64 ans = 0;
for (int i = 0, s = 0; i < N; ++i) {
s += cnt[i];
ans += std::min(s, n - s);
}
std::cout << ans << "\n";
}
倍增可以 按位和二分查询
题目
l区间and >= k 的最右侧 r
#include <bits/stdc++.h>
using i64 = long long;
void solve() {
int n;
std::cin >> n;
std::vector<int> a(n);
for (int i = 0; i < n; ++i) {
std::cin >> a[i];
}
int L = std::__lg(n);
std::vector val(L + 1, std::vector<int>(n));
val[0] = a;
for (int i = 0; i < L; ++i) {
for (int j = 0; j + (1 << i) < n; ++j) {
val[i + 1][j] = val[i][j] & val[i][j + (1 << i)];
}
}
auto qry = [&](int l, int r) -> int {
int len = std::__lg(r - l);
return val[len][l] & val[len][r - (1 << len)];
};
int q;
std::cin >> q;
for (int i = 0; i < q; ++i) {
int l, k;
std::cin >> l >> k;
--l;
int lo = l, hi = n;
while (lo < hi) {
auto mid = lo + (hi - lo + 1) / 2;
if (qry(l, mid) >= k) {
lo = mid;
} else {
hi = mid - 1;
}
}
std::cout << (lo == l ? -1 : lo) << " ";
// int x = (1 << 30) - 1;
// int p = l;
// for (int j = L; j >= 0 && p < n; --j) {
// if ((val[j][p] & x) >= k) {
// x &= val[j][p];
// p += 1 << j;
// }
// }
// std::cout << (p == l ? -1 : p) << " ";
}
std::cout << std::endl;
}
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
int t;
std::cin >> t;
while (t--) {
solve();
}
}
二分图判断 DSU
博客有一场CF E题
Codeforces Round 805 (Div. 3)

浙公网安备 33010602011771号