首先之前的首先,我先宣布一下这个帖子作废了,但是还留着做纪念吧出新版了,大家可以看看哦~
首先,感谢@林海威大佬的“题解”让我有了思路
于是,我也决定来一波恐怖的题解!
时隔两年多,卷土重来!
啊这个帖子当我练练手吧……
😱😱😱
啊,对了,为了防止误导新人,先奉上一个非常正常的蒟蒻版代码:
#include <bits/stdc++.h>
using namespace std;
int a, b;
int main() {
scanf("%d%d", &a, &b);
printf("%d\n", a + b);
return 0;
}
啊那个啥?
你不信都AC了?
自己测试去吧!
而且有些算法比直接A+B还要快几毫秒……
本“题解”参考了林海威大佬的“题解”,还有洛谷的部分“题解”
为什么加上删除线呢?因为这些都不是正经的题解
现在开始!
算法一、DFS一号
#include <bits/stdc++.h>
using namespace std;
int n = 2, a[5], s;
int dfs(int x, int sum) {
if (x > n) return sum;
int i = dfs(x + 1, sum);
int j = dfs(x + 1, sum + a[x]);
if (i == s) return i;
if (j == s) return j;
return -1;
}
int main() {
for (int i = 1;i <= n; i++) scanf("%d", &a[i]), s += a[i];
cout << dfs(1, 0) << endl;
return 0;
}
算法二、DFS二号
#include <bits/stdc++.h>
using namespace std;
int a, b;
int dfs(int x) {
if (x <= 5) return x;
return dfs(x / 2) + dfs(x - x / 2);
}
int main() {
scanf("%d%d", &a, &b);
printf("%d\n", dfs(a) + dfs(b));
return 0;
}
算法三、BFS
#include <bits/stdc++.h>
using namespace std;
int n = 2, a[5], s;
queue<int> q;
void bfs() {
q.push(0);
int c = 0;
while (q.size()) {
c++;
int f = q.front(); q.pop();
if (f == s) {printf("%d\n", f); exit(0);}
q.push(f + a[c]);
q.push(f);
}
}
int main() {
for (int i = 1;i <= n; i++) scanf("%d", &a[i]), s += a[i];
bfs();
return 0;
}
算法四、直接算咯
#include <bits/stdc++.h>
using namespace std;
int a, b;
int main() {
scanf("%d%d", &a, &b);
printf("%d\n", a + b);
return 0;
}
算法五、二分
#include <bits/stdc++.h>
using namespace std;
int a, b;
int main() {
scanf("%d%d", &a, &b);
int l = 0, r = 200000000;
while (l < r) {
int mid = l + r >> 1;
if (mid == a + b) {printf("%d\n", mid); return 0;}
if (mid < a + b) l = mid + 1;
if (mid > a + b) r = mid - 1;
}
cout << l << endl;
return 0;
}
算法六、稍微有点暴力的枚举
但是还是$1892ms$卡过了欸
#include <bits/stdc++.h>
using namespace std;
int a, b;
int main() {
scanf("%d%d", &a, &b);
for (int i = 0;i <= 200000000; i++) if (a + b == i) {printf("%d\n", i); break;}
return 0;
}
算法七、最短路之dijkstra
思路:定义节点1到节点2路径长度为a,节点2到节点3路径长度为b
则答案为节点1到节点3的最短路(也就是$a+b$)
#include <bits/stdc++.h>
using namespace std;
int w[5][5], d[5], v[5];
int n = 3;
void dijkstra() {
memset(d, 0x3f, sizeof d);
memset(v, 0, sizeof v);
d[1] = 0;
for (int i = 1;i < n; i++) {
int x = 0;
for (int j = 1;j <= n; j++)
if (!v[j] && (x == 0 || d[j] < d[x])) x = j;
v[x] = 1;
for (int y = 1;y <= n; y++)
d[y] = min(d[y], d[x] + w[x][y]);
}
}
int main() {
int a, b; scanf("%d%d", &a, &b);
memset(w, 0x3f, sizeof w);
w[1][2] = a; w[2][3] = b;
dijkstra();
printf("%d\n", d[3]);
return 0;
}
算法八、最短路之SPFA
思路同上
#include <bits/stdc++.h>
using namespace std;
int a, b, n = 3;
int w[5][5], d[5], v[5];
queue<int> q;
void spfa() {
memset(d, 0x3f, sizeof d);
memset(v, 0, sizeof v);
d[1] = 0, v[1] = 1;
q.push(1);
while (q.size()) {
int x = q.front(); q.pop();
v[x] = 0;
for (int i = 1;i <= n; i++) {
// if (w[x][i] == 0x3f) continue;
if (d[i] > d[x] + w[x][i]) {
d[i] = d[x] + w[x][i];
if (!v[i]) q.push(i), v[i] = 1;
}
}
}
}
int main() {
scanf("%d%d", &a, &b);
memset(w, 0x3f, sizeof w);
w[1][2] = a; w[2][3] = b;
spfa();
printf("%d\n", d[3]);
return 0;
}
算法九、最短路之Floyd
思路同上
#include <bits/stdc++.h>
using namespace std;
int d[5][5], n = 3;
int main() {
int a, b; scanf("%d%d", &a, &b);
memset(d, 0x3f, sizeof d);
d[1][2] = a; d[2][3] = b;
for (int k = 1;k <= n; k++)
for (int i = 1;i <= n; i++)
for (int j = 1;j <= n; j++)
d[i][j] = min(d[i][j], d[i][k] + d[k][j]);
printf("%d\n", d[1][3]);
return 0;
}
算法十、高精
#include<bits/stdc++.h>
using namespace std;
string a0, b0;
int a[1005], b[1005];
int main(){
cin >> a0 >> b0;
int l1 = a0.size(), l2 = b0.size();
for (int i = 0;i < l1; i++) a[l1 - i] = a0[i] - 48;
for (int i = 0;i < l2; i++) b[l2 - i] = b0[i] - 48;
l1 = max(l1, l2);
for (int i = 1;i <= l1; i++) {
a[i] += b[i];
if (a[i] > 9) a[i + 1] += 1, a[i] %= 10;
}
if (a[max(l1, l2) + 1] > 0) l1++;
for (int i = l1;i >= 1; i--) printf("%d", a[i]);
return 0;
}
算法十一、最小生成树之kruskal
思路其实和最短路的一样,只是改成用最小生成树的方法求罢了
#include <bits/stdc++.h>
using namespace std;
struct rec {
int x, y, z;
} edge[5];
int fa[5], m = 2, ans = 0;
int get(int x) {
if (x == fa[x]) return x;
return fa[x] = get(fa[x]);
}
int cmp(rec a, rec b) { return a.z < b.z; }
int main() {
int a, b; scanf("%d%d", &a, &b);
edge[1] = (rec){1, 2, a};
edge[2] = (rec){2, 3, b};
for (int i = 1;i <= m + 1; i++) fa[i] = i;
sort(edge + 1, edge + 1 + m, cmp);
for (int i = 1;i <= m; i++) {
int x = get(edge[i].x);
int y = get(edge[i].y);
if (x == y) continue;
fa[x] = y;
ans += edge[i].z;
}
printf("%d\n", ans);
return 0;
}
算法十二、最小生成树之prim
思路同上
#include <bits/stdc++.h>
using namespace std;
int w[5][5], d[5], n = 3, ans, v[5];
void prim() {
memset(d, 0x3f, sizeof d);
memset(v, 0, sizeof v);
d[1] = 0;
for (int i = 1;i < n; i++) {
int x = 0;
for (int j = 1;j <= n; j++)
if (!v[j] && (x == 0 || d[j] < d[x])) x = j;
v[x] = 1;
for (int y = 1;y <= n; y++)
if (!v[y]) d[y] = min(d[y], w[x][y]);
}
}
int main() {
int a, b; scanf("%d%d", &a, &b);
memset(w, 0x3f, sizeof w);
w[1][2] = a; w[2][3] = b;
prim();
int ans = 0;
for (int i = 2;i <= n; i++) ans += d[i];
printf("%d\n", ans);
return 0;
}
算法十三、前缀和
#include <bits/stdc++.h>
using namespace std;
int a[5], s[5];
int main() {
for (int i = 1;i <= 2; i++) scanf("%d", &a[i]), s[i] += a[i] + s[i - 1];
printf("%d\n", s[2]);
return 0;
}
算法十四、后缀和
#include <bits/stdc++.h>
using namespace std;
int a[5], s[5];
int main() {
for (int i = 2;i >= 1; i--) scanf("%d", &a[i]), s[i] += a[i] + s[i + 1];
printf("%d\n", s[1]);
return 0;
}
算法十五、位运算
#include <bits/stdc++.h>
using namespace std;
int add(int a, int b) {
if (b == 0) return a;
return add(a ^ b, (a & b) << 1);
}
int main() {
int a, b; scanf("%d%d", &a, &b);
printf("%d\n", add(a, b));
return 0;
}
算法十六、树的直径——BFS
emmm……思路继续和最短路的一样。。。
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 10;
int head[maxn * 2],edge[maxn * 2],Next[maxn * 2],ver[maxn * 2];
int vis[maxn], dist[maxn];
int n = 3, p, q, d;
int tot = 0;
int maxd = 0;
void add(int u,int v,int w) {
ver[ ++ tot] = v,edge[tot] = w;
Next[tot] = head[u],head[u] = tot;
}
int BFS(int u) {
queue<int>Q;
while(!Q.empty()) Q.pop();
memset(vis, 0, sizeof vis);
memset(dist, 0, sizeof dist);
Q.push(u);
int x, max_num = 0;
while(!Q.empty()) {
x = Q.front();
Q.pop();
vis[x] = 1;
for(int i = head[x]; i ; i = Next[i]) {
int y = ver[i];
if(vis[y]) continue;
vis[y] = 1;
dist[y] = dist[x] + edge[i];
if(dist[y] > maxd) {
maxd = dist[y];
max_num = y;
}
Q.push(y);
}
}
return max_num;
}
int main(void) {
int a, b; scanf("%d%d", &a, &b);
add(1, 2, a); add(2, 1, a);
add(2, 3, b); add(3, 2, b);
BFS(BFS(1));
int ans = 0;
for (int i = 1;i <= n; i++) ans = max(ans, dist[i]);
printf("%d\n", ans);
return 0;
}
算法十七、树的直径——DFS
思路同上
#include<bits/stdc++.h>
#define maxn 100000
using namespace std;
struct node {
int u, v, w, nex;
} edge[2 * maxn + 10];
int n = 3, d[maxn + 10], head[maxn + 10], f_num, cnt = 0, ans;
inline void add(int x,int y,int z) {
edge[++cnt].u = x;
edge[cnt].v = y;
edge[cnt].w = z;
edge[cnt].nex = head[x];
head[x] = cnt;
}
inline void dfs(int x, int fa) {
if(ans < d[x]) {
ans = d[x];
f_num = x;
}
for (int i = head[x]; i != -1; i = edge[i].nex) {
int j = edge[i].v;
if (j == fa)continue;
d[j] = d[x] + edge[i].w;
dfs(j, x);
}
}
int main() {
memset(head, -1, sizeof(head));
int a, b; scanf("%d%d", &a, &b);
add(1, 2, a); add(2, 1, a);
add(2, 3, b); add(3, 2, b);
dfs(1, 0);
ans = 0;
d[f_num] = 0;
dfs(f_num, 0);
for (int i = 1;i <= n; i++) ans = max(ans, d[i]);
printf("%d", ans);
return 0;
}
算法十八、树的直径——树形DP
还是一样咯
#include <bits/stdc++.h>
using namespace std;
int f[5], n = 3, cnt, h[5], ans, dis[5];
struct edge {
int to, next, vi;
} e[5];
void add(int u, int v, int w) {
e[cnt].to= v;
e[cnt].vi = w;
e[cnt].next = h[u];
h[u] = cnt++;
}
void dp(int u, int fa) {
for (int i = h[u]; ~i; i = e[i].next) {
int v = e[i].to;
if (v == fa) continue;
dp(v, u);
ans = max(ans, dis[v] + dis[u] + e[i].vi);
dis[u] = max(dis[u], dis[v] + e[i].vi);
}
}
int main() {
memset(h, -1, sizeof h);
int a, b; scanf("%d%d", &a, &b);
add(1, 2, a); add(2, 1, a);
add(2, 3, b); add(3, 2, b);
dp(1, 0);
printf("%d\n", ans);
return 0;
}
算法十九、网络流
从别的大佬那边搞过来的,但是一点都看不懂┭┮﹏┭┮
#include<bits/stdc++.h>
using namespace std;
#define set(x) Set(x)
#define REP(i,j,k) for (int i=(j),_end_=(k);i<=_end_;++i)
#define DREP(i,j,k) for (int i=(j),_start_=(k);i>=_start_;--i)
#define mp make_pair
#define x first
#define y second
#define pb push_back
template<typename T> inline bool chkmin(T &a,const T &b){ return a > b ? a = b, 1 : 0; }
template<typename T> inline bool chkmax(T &a,const T &b){ return a < b ? a = b, 1 : 0; }
typedef long long LL;
typedef pair<int,int> node;
const int dmax = 1010, oo = 0x3f3f3f3f;
int n, m;
int a[dmax][dmax] , ans;
int d[dmax], e[dmax];
priority_queue <node> q;
inline bool operator >(node a,node b){ return a.y>b.y; }
bool p[dmax];
void Set(int x){ p[x] = 1; }
void unset(int x){ p[x] = 0; }
bool check(int x){ return x != 1 && x != n && !p[x] && e[x] > 0; }
void preflow(){
e[1] = oo;
d[1] = n - 1;
q.push(mp(1, n - 1));
set(1);
while (!q.empty()) {
bool flag = 1;
int k = q.top().x;
q.pop(), unset(k);
DREP(i, n, 1)
if ((d[k] == d[i] + 1 || k == 1) && a[k][i] > 0){
flag = 0;
int t = min(a[k][i], e[k]);
e[k] -= t;
a[k][i] -= t;
e[i] += t;
a[i][k] += t;
if (check(i)) {
q.push(mp(i, d[i]));
set(i);
}
if (e[k] == 0) break;
}
if (flag) {
d[k] = oo;
REP(i, 1, n)
if (a[k][i] > 0) chkmin(d[k], d[i] + 1);
}
if (check(k)) {
q.push(mp(k, d[k]));
set(k);
}
}
ans = e[n];
}
int main() {
n = 2, m = 2;
int x, y;
scanf("%d%d", &x, &y);
a[1][2] += x + y;
preflow();
printf("%d\n", ans);
return 0;
}
算法二十、线段树
转化为区间求和问题
#include <bits/stdc++.h>
#define l(x) tree[x].l
#define r(x) tree[x].r
#define sum(x) tree[x].sum
#define add(x) tree[x].add
using namespace std;
struct SegmentTree {
int l, r; //区间左右端点
long long sum, add; //sum 区间和 add 延迟标记
} tree[400010];
int a[100010], n = 1, m = 2;
void build (int p, int l, int r) {
l(p) = l, r(p) = r;
if(l == r) {sum(p) = a[l]; return;}
int mid = l + r >> 1;
build(p * 2, l, mid);
build(p * 2 + 1, mid + 1, r);
sum(p) = sum(p * 2) + sum(p * 2 + 1);
}
void spread(int p) {
if(add(p)) { //节点p有标记
sum(p * 2) += add(p) * (r(p * 2) - l(p * 2) + 1); //更新左子节点信息
sum(p * 2 + 1) += add(p) * (r(p * 2 + 1) - l(p * 2 + 1) + 1); //更新右子节点
add(p * 2) += add(p); //给左子节点打延迟标记
add(p * 2 + 1) += add(p); //给右子节点打延迟标记
add(p) = 0; //清除p的标记
}
}
void change(int p, int l, int r, int d) {
if(l <= l(p) && r >= r(p)) { //完全覆盖
sum(p) += (long long) d * (r(p) - l(p) + 1); //更新节点信息
add(p) += d; //给节点打延迟标记
return;
}
spread(p); //下传延迟标记
int mid = l(p) + r(p) >> 1;
if(l <= mid) change(p * 2, l, r, d);
if(r > mid) change(p * 2 + 1, l, r, d);
sum(p) = sum(p * 2) + sum(p * 2 + 1);
}
long long ask(int p, int l, int r) {
if(l <= l(p) && r >= r(p)) return sum(p);
spread(p);
int mid = l(p) + r(p) >> 1;
long long val = 0;
if(l <= mid) val += ask(p * 2, l, r);
if(r > mid) val += ask(p * 2 + 1, l, r);
return val;
}
int main() {
a[1] = 0;
build(1, 1, n);
while(m--) {
int d = 0;
scanf("%d", &d);
change(1, 1, 1, d);
}
printf("%lld\n", ask(1, 1, 1));
return 0;
}
算法二十一、树状数组
思路一样,区间求和
#include<bits/stdc++.h>
using namespace std;
const int SIZE = 100010;
int a[SIZE], n = 1, m = 2;
long long c[2][SIZE], sum[SIZE];
long long ask(int k, int x) {
long long ans = 0;
for(; x ; x -= x & -x) ans += c[k][x];
return ans;
}
void add(int k,int x,int y) {
for(; x <= n; x += x & -x) c[k][x] += y;
}
int main() {
a[1] = 0;
while(m--) {
int d = 0;
scanf("%d", &d);
add(0, 1, d);
add(0, 2, -d);
add(1, 1, d);
add(1, 2, -2 * d);
}
long long ans = sum[1] + 2 * ask(0, 1) - ask(1, 1);
ans -= sum[0] + 1 * ask(0, 0) - ask(1, 0);
printf("%lld\n", ans);
return 0;
}
算法二十二、分块
思路一样,区间求和
#include<bits/stdc++.h>
using namespace std;
long long a[50000010], sum[50000010], add[50000010];
int L[50000010], R[50000010];
int pos[50000010];
int n = 1, m = 2, t;
void change(int l, int r, long long d) {
int p = pos[l], q = pos[r];
if (p == q) {
for (int i = l; i <= r; i++) a[i] += d;
sum[p] += d*(r - l + 1);
}
else {
for (int i = p + 1; i <= q - 1; i++) add[i] += d;
for (int i = l; i <= R[p]; i++) a[i] += d;
sum[p] += d*(R[p] - l + 1);
for (int i = L[q]; i <= r; i++) a[i] += d;
sum[q] += d*(r - L[q] + 1);
}
}
long long ask(int l, int r) {
int p = pos[l], q = pos[r];
long long ans = 0;
if (p == q) {
for (int i = l; i <= r; i++) ans += a[i];
ans += add[p] * (r - l + 1);
}
else {
for (int i = p + 1; i <= q - 1; i++)
ans += sum[i] + add[i] * (R[i] - L[i] + 1);
for (int i = l; i <= R[p]; i++) ans += a[i];
ans += add[p] * (R[p] - l + 1);
for (int i = L[q]; i <= r; i++) ans += a[i];
ans += add[q] * (r - L[q] + 1);
}
return ans;
}
int main() {
a[1] = 0;
t = sqrt(n*1.0);
for (int i = 1; i <= t; i++) {
L[i] = (i - 1)*sqrt(n*1.0) + 1;
R[i] = i*sqrt(n*1.0);
}
if (R[t] < n) t++, L[t] = R[t - 1] + 1, R[t] = n;
for (int i = 1; i <= t; i++)
for (int j = L[i]; j <= R[i]; j++) {
pos[j] = i;
sum[i] += a[j];
}
while (m--) {
int d;
scanf("%d", &d);
change(1, 1, d);
}
printf("%lld\n", ask(1, 1));
}
算法二十三、LCT
嘿嘿(●ˇ∀ˇ●)
洛谷加油!洛谷加油!
啊又是洛谷来的快递。。。我一点都看不懂┭┮﹏┭┮
#include<bits/stdc++.h>
using namespace std;
struct node
{
int data,rev,sum;
node *son[2],*pre;
bool judge();
bool isroot();
void pushdown();
void update();
void setson(node *child,int lr);
}lct[233];
int top,a,b;
node *getnew(int x)
{
node *now=lct+ ++top;
now->data=x;
now->pre=now->son[1]=now->son[0]=lct;
now->sum=0;
now->rev=0;
return now;
}
bool node::judge()
{
return pre->son[1]==this;
}
bool node::isroot()
{
if(pre==lct)return true;
return !(pre->son[1]==this||pre->son[0]==this);
}
void node::pushdown()
{
if(this==lct||!rev)return;
swap(son[0],son[1]);
son[0]->rev^=1;
son[1]->rev^=1;
rev=0;
}
void node::update()
{
sum=son[1]->sum+son[0]->sum+data;
}
void node::setson(node *child,int lr)
{
this->pushdown();
child->pre=this;
son[lr]=child;
this->update();
}
void rotate(node *now)
{
node *father=now->pre,*grandfa=father->pre;
if(!father->isroot()) grandfa->pushdown();
father->pushdown();
now->pushdown();
int lr=now->judge();
father->setson(now->son[lr^1],lr);
if(father->isroot()) now->pre=grandfa;
else grandfa->setson(now,father->judge());
now->setson(father,lr^1);
father->update();
now->update();
if(grandfa!=lct) grandfa->update();
}
void splay(node *now)
{
if(now->isroot())return;
for(; !now->isroot(); rotate(now))
if(!now->pre->isroot())
now->judge()==now->pre->judge()?rotate(now->pre):rotate(now);
}
node *access(node *now)
{
node *last=lct;
for(; now!=lct; last=now,now=now->pre) {
splay(now);
now->setson(last,1);
}
return last;
}
void changeroot(node *now)
{
access(now)->rev^=1;
splay(now);
}
void connect(node *x,node *y)
{
changeroot(x);
x->pre=y;
access(x);
}
void cut(node *x,node *y)
{
changeroot(x);
access(y);
splay(x);
x->pushdown();
x->son[1]=y->pre=lct;
x->update();
}
int query(node *x,node *y)
{
changeroot(x);
node *now=access(y);
return now->sum;
}
int main()
{
scanf("%d%d",&a,&b);
node *A=getnew(a);
node *B=getnew(b);
connect(A,B);
cut(A,B);
connect(A,B);
printf("%d",query(A,B));
return 0;
}
算法二十四、Splay
洛谷加油!
#include <bits/stdc++.h>
#define ll long long
#define N 100000
using namespace std;
int sz[N], rev[N], tag[N], sum[N], ch[N][2], fa[N], val[N];
int n, m, rt, x;
void push_up(int x){
sz[x] = sz[ch[x][0]] + sz[ch[x][1]] + 1;
sum[x] = sum[ch[x][1]] + sum[ch[x][0]] + val[x];
}
void push_down(int x){
if(rev[x]){
swap(ch[x][0], ch[x][1]);
if(ch[x][1]) rev[ch[x][1]] ^= 1;
if(ch[x][0]) rev[ch[x][0]] ^= 1;
rev[x] = 0;
}
if(tag[x]){
if(ch[x][1]) tag[ch[x][1]] += tag[x], sum[ch[x][1]] += tag[x];
if(ch[x][0]) tag[ch[x][0]] += tag[x], sum[ch[x][0]] += tag[x];
tag[x] = 0;
}
}
void rotate(int x, int &k){
int y = fa[x], z = fa[fa[x]];
int kind = ch[y][1] == x;
if(y == k) k = x;
else ch[z][ch[z][1]==y] = x;
fa[x] = z; fa[y] = x; fa[ch[x][!kind]] = y;
ch[y][kind] = ch[x][!kind]; ch[x][!kind] = y;
push_up(y); push_up(x);
}
void splay(int x, int &k){
while(x != k){
int y = fa[x], z = fa[fa[x]];
if(y != k) if(ch[y][1] == x ^ ch[z][1] == y) rotate(x, k);
else rotate(y, k);
rotate(x, k);
}
}
int kth(int x, int k){
push_down(x);
int r = sz[ch[x][0]]+1;
if(k == r) return x;
if(k < r) return kth(ch[x][0], k);
else return kth(ch[x][1], k-r);
}
void split(int l, int r){
int x = kth(rt, l), y = kth(rt, r+2);
splay(x, rt); splay(y, ch[rt][1]);
}
void rever(int l, int r){
split(l, r);
rev[ch[ch[rt][1]][0]] ^= 1;
}
void add(int l, int r, int v){
split(l, r);
tag[ch[ch[rt][1]][0]] += v;
val[ch[ch[rt][1]][0]] += v;
push_up(ch[ch[rt][1]][0]);
}
int build(int l, int r, int f){
if(l > r) return 0;
if(l == r){
fa[l] = f;
sz[l] = 1;
return l;
}
int mid = l + r >> 1;
ch[mid][0] = build(l, mid-1, mid);
ch[mid][1] = build(mid+1, r, mid);
fa[mid] = f;
push_up(mid);
return mid;
}
int asksum(int l, int r){
split(l, r);
return sum[ch[ch[rt][1]][0]];
}
int main(){
//总共两个数
n = 2;
rt = build(1, n+2, 0);//建树
for(int i = 1; i <= n; i++){
scanf("%d", &x);
add(i, i, x);//区间加
}
rever(1, n);//区间翻转
printf("%d\n", asksum(1, n));//区间求和
return 0;
}
算法二十五、LCA
洛谷加油!
#include<cstdio> //头文件
#define NI 2
//从来不喜欢算log所以一般用常数 不知道算不算坏习惯 因为3个节点 所以log3(当然以2为底)上取整得2
struct edge
{
int to,next,data; //分别表示边的终点,下一条边的编号和边的权值
}e[30]; //邻接表,点少边少开30是为了浪啊
int v[10],d[10],lca[10][NI+1],f[10][NI+1],tot=0; //数组开到10依然为了浪
//数组还解释嘛,v表示第一条边在邻接表中的编号,d是深度,lca[x][i]表示x向上跳2^i的节点,f[x][i]表示x向上跳2^i的距离和
void build(int x,int y,int z) //建边
{
e[++tot].to=y; e[tot].data=z; e[tot].next=v[x]; v[x]=tot;
e[++tot].to=x; e[tot].data=z; e[tot].next=v[y]; v[y]=tot;
}
void dfs(int x) //递归建树
{
for(int i=1;i<=NI;i++) //懒,所以常数懒得优化
f[x][i]=f[x][i-1]+f[lca[x][i-1]][i-1],
lca[x][i]=lca[lca[x][i-1]][i-1]; //建树的同时进行预处理
for(int i=v[x];i;i=e[i].next) //遍历每个连接的点
{
int y=e[i].to;
if(lca[x][0]==y) continue;
lca[y][0]=x; //小技巧:lca[x][0]即为x的父亲~~(向上跳2^0=1不就是父节点嘛)
f[y][0]=e[i].data;
d[y]=d[x]+1;
dfs(y); //再以这个节点为根建子树【这里真的用得到嘛??】
}
}
int ask(int x,int y) //询问,也是关键
{
if(d[x]<d[y]) {int t=x;x=y;y=t;} //把x搞成深的点
int k=d[x]-d[y],ans=0;
for(int i=0;i<=NI;i++)
if(k&(1<<i)) //若能跳就把x跳一跳
ans+=f[x][i], //更新信息
x=lca[x][i];
for(int i=NI;i>=0;i--) //不知道能不能正着循环,好像倒着优,反正记得倒着就好了
if(lca[x][i]!=lca[y][i]) //如果x跳2^i和y跳2^j没跳到一起就让他们跳
ans+=f[x][i]+f[y][i],
x=lca[x][i],y=lca[y][i];
return ans+f[x][0]+f[y][0]; //跳到LCA上去(每步跳的时候都要更新信息,而且要在跳之前更新信息哦~)
}
int main()
{
int a,b;
scanf("%d%d",&a,&b);
build(1,2,a);
build(1,3,b); //分别建1 2、1 3之间的边
dfs(1); //以1为根建树
printf("%d",ask(2,3)); //求解2 3到它们的LCA的距离和并输出
}
算法二十六、字典树
洛谷继续加油!
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
using namespace std;
struct node{
int str[26];
int sum;
}s[1000];
char str1[100];
int t=0,tot=0,ss=0;
bool f1;
void built()
{
t=0;
for(int i=0;i<strlen(str1);i++)
{
if(str1[i]=='-'){
f1=true;continue;
}
if(!s[t].str[str1[i]-'0'])
s[t].str[str1[i]-'0']=++tot;
t=s[t].str[str1[i]-'0'];
s[t].sum=str1[i]-'0';
}
}
int query()
{
int t=0;int s1=0;
for(int i=0;i<strlen(str1);i++)
{
if(str1[i]=='-') continue;
if(!s[t].str[str1[i]-'0']) return s1;
t=s[t].str[str1[i]-'0'];
s1=s1*10+s[t].sum;
}
return s1;
}
int main()
{
for(int i=1;i<=2;i++)
{
f1=false;
scanf("%s",str1);
built();
if(f1)
ss-=query();
else ss+=query();
}
printf("%d",ss);
return 0;
}
上面的26个解法都AC了(我测试过~你们不信可以自己试试去!)
接下来的解法不太正经。。。有些解法和那个特别正经的蒟蒻版直接算A+B没啥区别(根本没有区别)就是改了点格式。。。
小小声:都是从别人那里搞过来的奇葩代码。。。
还会陆续补充~
一、非常标准的绕圈代码
#include <bits/stdc++.h>
int __________=45,___________=5;
template<typename _>bool ________(_ __) {return __>=(__________+3)&&__<=(__________+12);}
template<typename _>void ___(_ __){if(__<(___________-5))__=abs(__),putchar('-');
if (__>(___________+4))___(__/(___________+5));putchar (__%(___________+5)+(__________+3));}
template<typename _>void ____(_ &__){__=(___________-5);_ _____=(__________-___________*9),______=getchar();
while(!________(______))_____^=!(______^__________),______=getchar();
while(________(______))__=(__<<1)+(__<<3)+(______&(__________-30)),______=getchar(); __=_____?-__:__;}
int main() {int _, __; ____(_); ____(__); ___(_+__);}
二、函数解法
#include <bits/stdc++.h>
using namespace std;
int add(int a, int b) { return a + b; }
int main() {
int a, b; scanf("%d%d", &a, &b);
printf("%d\n", add(a, b));
return 0;
}
三、结构体解法
#include <bits/stdc++.h>
using namespace std;
struct s{
int a, b;
}x;
int main() {
scanf("%d%d", &x.a, &x.b);
printf("%d\n", x.a + x.b);
return 0;
}
四、打表解法
这个测试数据只有@yxc大佬知道。。。
所以只有yxc大佬能用这个解法。。。
不过像y总这样的人生赢家肯定不会用这种可耻的打表的
但是
你们知道有些人打表写了3047行么???
就在$2021.10.6$的晚上$18:42$分
有个可耻的人私聊我
说他找到了A+B的打表解法
啊给大家分享一下这个$len$的可耻!
大家说这个人是不是闲的没事干!?!?
#include <bits/stdc++.h>
using namespace std;
int a, b; int main() {
scanf("%d%d", &a, &b);
if (a == 3 && b == 4) printf("7");
if (a == 45 && b == 55) printf("100");
if (a == 123 && b == 321) printf("444");
if (a == 91086199 && b == 18700332) printf("109786531");
if (a == 42267194 && b == 60645282) printf("102912476");
if (a == 69274392 && b == 10635835) printf("79910227");
if (a == 5710219 && b == 85140568) printf("90850787");
if (a == 75601477 && b == 24005804) printf("99607281");
if (a == 70597795 && b == 90383234) printf("160981029");
if (a == 82574652 && b == 22252146) printf("104826798");
return 0; //hh,这个len没加上return 0,还是我加的……
}
五、恐怖解法(AC一个点的成功率都≈0)
#include <bits/stdc++.h>
using namespace std;
int main() {
srand((unsigned)time(NULL));
int a = rand() % 100000000;
printf("%d\n", a);
return 0;
}
六、暴力$^2$解法
#include <bits/stdc++.h>
using namespace std;
int main() {
int a, b; scanf("%d%d", &a, &b);
for (int i = 1;i <= 100000000; i++)
for (int j = 1;j <= 100000000; j++)
if (a == i && b == j) printf("%d\n", i + j);
return 0;
}
所以说我退坑了两年acwing的A+B恶搞题解这么多了???
2333333333333333333333333333
终于见到
我师傅了????
你的题解让我有了思路……
nb
a + b acwing中最难题
HeHe……
所以才说能看懂A+B所有题解的人才是天才……
天生的蠢材(doge)咳咳咳……
啊啊啊周赛好难啊啊啊我又要垫底了啊啊啊
建议加入:不带堆优化的dijkstra,和bellman-ford,然后各种优化的spfa,还有各种求最近公共祖先的算法,可以多些几个(,应该能搞到30+,建议加入打表(面向答案编程)
hhh啊哈哈哈哈
# 大佬真是个天才!
######
我也是天才(天生的蠢材)好滴,我去试试看hhh
还有打表有了,在最后六种解法里面hhh
欧哈哈哈可以可以,%%%大佬,也可以加上差分qaq,就是先把a加进去,再把b加进去,然后求一个前缀和
再补充两个,高精乘法,算a1+b1,高精减法,找可以算负数的,a + b = a - (-b)
我真是聪(xian)明(de)绝(dan)顶(teng)
hh是
$a \times 1 + b \times 1$么?理解理解~
哦对了偶不系大佬……you才系大佬……
hhh先把STL的代码写了(几百行的代码写的我手疼……)
看了大佬的方法之后
#
我自闭了# 好难………………………………………………
是的,语法出了点问题
啊啊啊啊啊啊啊啊啊啊啊啊那所以还是高精度加法啊…………
我看不懂,但我大为震撼
hhh
都说了是:
# 有些
解法和那个特别正经的蒟蒻版直接算A+B没啥区别(根本没有区别)就是改了点格式。。。
不是说全部都能AC啊……
明摆着搞事情啊!
#
(小小声:不正经解法第五个我竟然AC3个点)# 啊啊啊本蒟蒻还没有食用它就炸了!!!啊啊啊
,好恐怖,还好没食用,不然我就炸了啊啊啊,我就见不到sun了啊啊啊………………………………
# 我要打五星差评啊啊啊
# 哼!😕
你们在干哈子。。。
你又在干哈子。。。
我在想你们在干哈子。。。
我也在想你在干哈子。。。
我在想你在想我在想你在干哈子。。。
我在想你在想我在想你在想我在干哈子。。。
我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在干哈子。。。
我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在想你在想我在干哈子。。。
hh
建议慢慢食用,不要心急一口吞下,
会炸掉加一个我的
好的~
但是我咋看不懂哩。。。
已加~
就
……
O懂了
……我这智商有点……