PTA天梯赛2017GPLT

7-6 整除光棍

给定一个不以5结尾的奇数\(x\),求出数字\(n\)使得\(n*x=11...111\),输出数字n和1的位数

题解:模拟竖式除法

我们一开始发现n只要一直往后*10+1一定就会出现\(n\%x=0\),但是很显然n一定会很大,所以我们可以试着优化;我们在模拟竖式除法时发现:我们每次的被除数可以用前一次计算的余数表示,即\((n\%x)×10+1\),那么这样就解决了n很大的问题,\(n/x\)就是答案的每一位,但是我们要注意很有可能会有前导0,所以我们可以先让\(n>x\)

#include <bits/stdc++.h>
#define Zeoy std::ios::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0)
#define debug(x) cerr << #x << '=' << x << endl
#define all(x) (x).begin(), (x).end()
#define rson id << 1 | 1
#define lson id << 1
#define int long long
#define mpk make_pair
#define endl '\n'
using namespace std;
typedef unsigned long long ULL;
typedef long long ll;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
const int mod = 1e9 + 7;
const double eps = 1e-9;
const int N = 2e5 + 10, M = 4e5 + 10; int x; void solve()
{
cin >> x;
ULL n = 1;
int num = 1;
ULL ans = 0;
while (n < x)
{
n = n * 10 + 1;
num++;
}
while (1)
{
cout << n / x;
if (n % x == 0)
break;
n %= x;
n = n * 10 + 1;
num++;
}
cout << " ";
cout << num << endl;
}
signed main(void)
{
Zeoy;
int T = 1;
// cin >> T;
while (T--)
{
solve();
}
return 0;
}

7-10 重排链表

给定一个单链表 L1→L2→⋯→Ln−1→Ln,请编写程序将链表重新排列为 LnL1→Ln−1→L2→⋯。例如:给定L为1→2→3→4→5→6,则输出应该为6→1→5→2→4→3。

Input
00100 6
00000 4 99999
00100 1 12309
68237 6 -1
33218 3 00000
99999 5 68237
12309 2 33218
Output
68237 6 00100
00100 1 99999
99999 5 12309
12309 2 00000
00000 4 33218
33218 3 -1

题解:单链表

考察数据结构单链表的使用,我们使用数组模拟即可,我们只需要通过\(address\)数组记录每个节点的地址即可,然后通过题目可以知道我们可以使用双指针

#include <bits/stdc++.h>
#define Zeoy std::ios::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0)
#define debug(x) cerr << #x << '=' << x << endl
#define all(x) (x).begin(), (x).end()
#define rson id << 1 | 1
#define lson id << 1
#define int long long
#define mpk make_pair
#define endl '\n'
using namespace std;
typedef unsigned long long ULL;
typedef long long ll;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
const int mod = 1e9 + 7;
const double eps = 1e-9;
const int N = 2e5 + 10, M = 4e5 + 10; int head, e[N], ne[N];
int n;
int add[N]; void solve()
{
cin >> head >> n;
int cnt = 0;
for (int i = 1; i <= n; ++i)
{
int idx, val, next;
cin >> idx >> val >> next;
e[idx] = val;
ne[idx] = next;
}
int pos = head;
while (pos != -1)
{
add[++cnt] = pos;
pos = ne[pos];
}
int l = 1, r = cnt;
head = add[cnt];
while (l < r)
{
ne[add[r]] = add[l];
r--;
ne[add[l]] = add[r];
l++;
ne[add[r]] = add[l];
}
ne[add[r]] = -1;
pos = head;
while (pos != -1)
{
if (~ne[pos])
printf("%05d %d %05d\n", pos, e[pos], ne[pos]);
else
printf("%05d %d -1\n", pos, e[pos]);
pos = ne[pos];
}
}
signed main(void)
{
Zeoy;
int T = 1;
// cin >> T;
while (T--)
{
solve();
}
return 0;
}

7-11 图着色问题

图着色问题是一个著名的NP完全问题。给定无向图G=(V,E),问可否用K种颜色为V中的每一个顶点分配一种颜色,使得不会有两个相邻顶点具有同一种颜色?

但本题并不是要你解决这个着色问题,而是对给定的一种颜色分配,请你判断这是否是图着色问题的一个解。

题解:dfs染色法

注意该图很有可能不是连通图,可能是由许多连通块组成的,所以我们需要对每一个连通块dfs

#include <bits/stdc++.h>
#define Zeoy std::ios::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0)
#define debug(x) cerr << #x << '=' << x << endl
#define all(x) (x).begin(), (x).end()
#define rson id << 1 | 1
#define lson id << 1
#define int long long
#define mpk make_pair
#define endl '\n'
using namespace std;
typedef unsigned long long ULL;
typedef long long ll;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
const int mod = 1e9 + 7;
const double eps = 1e-9;
const int N = 1e5 + 10, M = 4e5 + 10; vector<int> g[N];
int n, m, k, q;
int vis[N];
int a[N]; bool dfs(int u, int col)
{
vis[u] = col;
for (auto v : g[u])
{
if (!vis[v])
{
if (!dfs(v, a[v]))
return false;
}
else if (vis[v] == col)
return false;
}
return true;
} void solve()
{
cin >> n >> m >> k;
for (int i = 1, u, v; i <= m; ++i)
{
cin >> u >> v;
g[u].push_back(v);
g[v].push_back(u);
}
cin >> q;
while (q--)
{
set<int> st;
for (int i = 1; i <= n; ++i)
vis[i] = 0;
for (int i = 1; i <= n; ++i)
{
cin >> a[i];
st.insert(a[i]);
}
int cnt = 0;
for (auto i : st)
cnt++;
if (cnt > k || cnt < k)
{
cout << "No" << endl;
continue;
}
bool flag = flag;
for (int i = 1; i <= n; ++i) //我们需要对每一个连通块dfs
if (!vis[i])
{
flag = dfs(i, a[i]);
if (!flag)
break;
}
if (!flag)
cout << "No" << endl;
else
cout << "Yes" << endl;
}
}
signed main(void)
{
Zeoy;
int T = 1;
// cin >> T;
while (T--)
{
solve();
}
return 0;
}

7-13 二叉搜索树的结构

二叉搜索树或者是一棵空树,或者是具有下列性质的二叉树: 若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值;若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值;它的左、右子树也分别为二叉搜索树。

给定一系列互不相等的整数,将它们顺次插入一棵初始为空的二叉搜索树,然后对结果树的结构进行描述。你需要能判断给定的描述是否正确。

题解:

首先我们要知道二叉搜索树的概念,我们将一系列整数插入一颗初始为空的二叉搜索树,根据定义得知,我们每次插入一个点,必须从根节点开始遍历

  1. 我们来讲一讲二叉搜索树的建树过程:

    首先第一个数一定是二叉搜索树的根,然后我们对数组中的每一个数进行dfs,假设当前插入的数为\(val\),那么如果\(val\)比当前\(dfs\)遍历到的节点\(u\)的值小,那么\(val\)应该位于它的左子树范围内,如果说u节点没有左儿子,那么我们就找到了要插入的地方,所以我们新建一个点,\(idx++\)(idx代表当前树上节点的数量,类似单链表),同时我们可以利用\(map\)存储每个节点对应的下标,这样方便处理询问,比如样例中的1对应下标为2,即\(mp[1]=2\),

如果说u节点有左儿子,那么我们可以直接递归u节点的左儿子;

同理对于\(val\)比当前\(dfs\)遍历到的节点\(u\)的值大,也是一样,不再赘述

  1. 我们来讲一下节点需要存储的信息:

深度\(dep\),父亲节点的下标\(fa\),左儿子的下标\(lson\),右儿子的下标\(rson\),当前节点的值\(val\)

#include <bits/stdc++.h>
#define Zeoy std::ios::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0)
#define debug(x) cerr << #x << '=' << x << endl
#define all(x) (x).begin(), (x).end()
// #define rson id << 1 | 1
// #define lson id << 1
#define int long long
#define mpk make_pair
#define endl '\n'
using namespace std;
typedef unsigned long long ULL;
typedef long long ll;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
const int mod = 1e9 + 7;
const double eps = 1e-9;
const int N = 1e3 + 10, M = 4e5 + 10; int n;
int a[N];
struct node
{
int val;
int dep;
int fa;
int lson;
int rson;
} e[N];
int idx;
map<int, int> mp; void dfs(int u, int val)
{
if (val < e[u].val)
{
if (!e[u].lson)
{
e[u].lson = ++idx;
e[idx] = {val, e[u].dep + 1, u, 0, 0};
mp[val] = idx;
return;
}
else
dfs(e[u].lson, val);
}
else
{
if (!e[u].rson)
{
e[u].rson = ++idx;
e[idx] = {val, e[u].dep + 1, u, 0, 0};
mp[val] = idx;
return;
}
else
dfs(e[u].rson, val);
}
} void solve()
{
cin >> n;
for (int i = 1; i <= n; ++i)
cin >> a[i];
e[++idx] = {a[1], 1, 0, 0, 0};
mp[a[1]] = idx;
for (int i = 2; i <= n; ++i)
dfs(1, a[i]);
int rt = a[1]; int q;
cin >> q;
while (q--)
{
int u, v;
string s;
cin >> u;
cin >> s;
if (s == "is")
{
cin >> s;
cin >> s;
if (s == "root")
{
if (u == rt)
cout << "Yes" << endl;
else
cout << "No" << endl;
}
else if (s == "parent")
{
cin >> s;
cin >> v;
if (e[mp[v]].fa == mp[u] && mp[u] != 0 && mp[v] != 0)
cout << "Yes" << endl;
else
cout << "No" << endl;
}
else if (s == "left")
{
cin >> s;
cin >> s;
cin >> v;
if (e[mp[v]].lson == mp[u] && mp[u] != 0 && mp[v] != 0)
cout << "Yes" << endl;
else
cout << "No" << endl;
}
else if (s == "right")
{
cin >> s;
cin >> s;
cin >> v;
if (e[mp[v]].rson == mp[u] && mp[u] != 0 && mp[v] != 0)
cout << "Yes" << endl;
else
cout << "No" << endl;
}
}
else if (s == "and")
{
cin >> v;
cin >> s;
cin >> s;
if (s == "siblings")
{
if (e[mp[u]].fa == e[mp[v]].fa && mp[u] != 0 && mp[v] != 0)
cout << "Yes" << endl;
else
cout << "No" << endl;
}
else
{
if (e[mp[u]].dep == e[mp[v]].dep && mp[u] != 0 && mp[v] != 0)
cout << "Yes" << endl;
else
cout << "No" << endl;
cin >> s;
cin >> s;
cin >> s;
}
}
}
}
signed main(void)
{
Zeoy;
int T = 1;
// cin >> T;
while (T--)
{
solve();
}
return 0;
}

7-14 森森快递

森森开了一家快递公司,叫森森快递。因为公司刚刚开张,所以业务路线很简单,可以认为是一条直线上的N个城市,这些城市从左到右依次从0到(N−1)编号。由于道路限制,第i号城市(i=0,⋯,N−2)与第(i+1)号城市中间往返的运输货物重量在同一时刻不能超过\(C_i\)公斤。

公司开张后很快接到了Q张订单,其中j张订单描述了某些指定的货物要从\(S_j\)号城市运输到\(T_j\)号城市。这里我们简单地假设所有货物都有无限货源,森森会不定时地挑选其中一部分货物进行运输。安全起见,这些货物不会在中途卸货。

为了让公司整体效益更佳,森森想知道如何安排订单的运输,能使得运输的货物重量最大且符合道路的限制?要注意的是,发货时间有可能是任何时刻,所以我们安排订单的时候,必须保证共用同一条道路的所有货车的总重量不超载。例如我们安排1号城市到4号城市以及2号城市到4号城市两张订单的运输,则这两张订单的运输同时受2-3以及3-4两条道路的限制,因为两张订单的货物可能会同时在这些道路上运输。

题解: 贪心+线段树维护区间最小值和区间修改

首先对于两端区间\([a,b],[c,d]\)来说,对答案产生贡献会存在三种情况:

  1. \([a,b]和[c,d]\)之前不存在交集,那么这两个订单可以同时执行,不存在冲突和限制
  2. \(若[c,d]内含于[a,b]\),那么我们只能执行\([c,d]\)这个订单
  3. \(若[c,d]和[a,b]的交集为[b,c]\),那么此时最大运输货物重量为\(min(min[b,c],min[a,c]+min[b,d])\)

综上所述:我们发现我们只要对询问区间按照区间右端点升序排列,然后对于排序之后的区间从左到右遍历,我们每次利用线段树求出区间最小值后,再将这段区间所有承重全部减去最大货物重量,即可贪心求出答案

#include <bits/stdc++.h>
#define Zeoy std::ios::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0)
#define debug(x) cerr << #x << '=' << x << endl
#define all(x) (x).begin(), (x).end()
#define rson id << 1 | 1
#define lson id << 1
#define int long long
#define mpk make_pair
#define endl '\n'
using namespace std;
typedef unsigned long long ULL;
typedef long long ll;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
const int mod = 1e9 + 7;
const double eps = 1e-9;
const int N = 1e5 + 10, M = 4e5 + 10; int n, q;
struct Node
{
int l, r;
bool operator<(const Node &t) const
{
if (r != t.r)
return r < t.r;
else
return l < t.l;
}
};
vector<Node> a;
int w[N];
struct info
{
int minn;
};
struct node
{
int l, r, lazy;
info val;
} seg[N << 2];
info operator+(const info &a, const info &b)
{
info c;
c.minn = min(a.minn, b.minn);
return c;
} void settag(int id, int tag)
{
seg[id].val.minn += tag;
seg[id].lazy += tag;
} void up(int id)
{
seg[id].val = seg[lson].val + seg[rson].val;
} void down(int id)
{
if (seg[id].lazy == 0)
return;
settag(lson, seg[id].lazy);
settag(rson, seg[id].lazy);
seg[id].lazy = 0;
} void build(int id, int l, int r)
{
seg[id].l = l, seg[id].r = r;
int mid = l + r >> 1;
if (l == r)
{
seg[id].val.minn = w[l];
return;
}
build(lson, l, mid);
build(rson, mid + 1, r);
up(id);
} void modify(int id, int ql, int qr, int val)
{
int l = seg[id].l, r = seg[id].r;
int mid = l + r >> 1;
if (ql <= l && r <= qr)
{
settag(id, val);
return;
}
down(id);
if (qr <= mid)
modify(lson, ql, qr, val);
else if (ql > mid)
modify(rson, ql, qr, val);
else
{
modify(lson, ql, qr, val);
modify(rson, ql, qr, val);
}
up(id);
} info query(int id, int ql, int qr)
{
int l = seg[id].l, r = seg[id].r;
int mid = l + r >> 1;
if (ql <= l && r <= qr)
return seg[id].val;
down(id);
if (qr <= mid)
return query(lson, ql, qr);
else if (ql > mid)
return query(rson, ql, qr);
else
return query(lson, ql, qr) + query(rson, ql, qr);
} void solve()
{
cin >> n >> q;
for (int i = 1; i < n; ++i)
cin >> w[i];
build(1, 1, n - 1);
while (q--)
{
int l, r;
cin >> l >> r;
if (l > r)
swap(l, r);
l++;
a.push_back({l, r});
}
sort(all(a));
int ans = 0;
for (auto [l, r] : a)
{
int tmp = query(1, l, r).minn;
ans += tmp;
modify(1, l, r, -tmp);
}
cout << ans << endl;
}
signed main(void)
{
Zeoy;
int T = 1;
// cin >> T;
while (T--)
{
solve();
}
return 0;
}

7-15 森森美图

给定你坐标矩阵中起始点A和终点B,让你求出两条互不经过A,B之间连线的点的两条最短路径之和

题解: 最短路+计算几何(叉积)

很显然是最短路问题,我们可以选择spfa或者dijstra求解,但是我们这边如何去引导spfa要么往上走要么往下走呢,我们可以利用叉积,虽然叉积是三维向量的乘积,但是我们只需让z坐标为0即可,设起点为A,终点为B,图上任意一点为C:

  1. 如果\(\vec{AB}×\vec{AC}>0\),说明C在向量AB逆时针旋转<180°的方向上,或者在样例中是直线AB的右上方
  2. 如果\(\vec{AB}×\vec{AC}<0\),说明C在向量AB逆时针旋转>180°的方向上,或者在样例中是直线AB的左下方
  3. 如果\(\vec{AB}×\vec{AC}=0\),说明C于直线AB共线

那么我们只要进行两次spfa即可,第二次只要交换起始点位置即可,但是我们要注意起点和终点对答案的贡献多加了一次,最后需要减去。

#include <bits/stdc++.h>
#define Zeoy std::ios::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0)
#define debug(x) cerr << #x << '=' << x << endl
#define all(x) (x).begin(), (x).end()
#define rson id << 1 | 1
#define lson id << 1
#define int long long
#define mpk make_pair
#define endl '\n'
using namespace std;
typedef unsigned long long ULL;
typedef long long ll;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
const int mod = 1e9 + 7;
const double eps = 1e-9;
const int N = 1e2 + 10, M = 4e5 + 10; int n, m;
double a[N][N];
int sy, sx, ey, ex;
int vis[N][N];
double dis[N][N];
int dir1[4][2] = {{-1, 0}, {0, -1}, {1, 0}, {0, 1}};
int dir2[4][2] = {{-1, -1}, {-1, 1}, {1, 1}, {1, -1}};
const double k = sqrt(2) - 1;
double ans = 0.0; int cal(pii p1, pii p2)
{
auto [x1, y1] = p1;
auto [x2, y2] = p2;
return (x1 * y2 - y1 * x2);
} void spfa(int sx, int sy)
{
memset(vis, 0, sizeof vis);
for (int i = 0; i < n; ++i)
for (int j = 0; j < m; ++j)
dis[i][j] = inf;
queue<pii> q;
q.push({sx, sy});
dis[sx][sy] = a[sx][sy];
vis[sx][sy] = 1;
while (q.size())
{
auto [x, y] = q.front();
// cout << x << " " << y << endl;
q.pop();
vis[x][y] = 0;
for (int i = 0; i < 4; ++i)
{
int nx = x + dir1[i][0];
int ny = y + dir1[i][1];
if ((nx >= 0 && nx < n && ny >= 0 && ny < m && cal(mpk(ex - sx, ey - sy), mpk(nx - sx, ny - sy)) > 0) || (nx == ex && ny == ey))
{
if (dis[nx][ny] > dis[x][y] + a[nx][ny])
{
dis[nx][ny] = dis[x][y] + a[nx][ny];
if (!vis[nx][ny])
q.push({nx, ny}), vis[nx][ny] = 1;
}
}
}
for (int i = 0; i < 4; ++i)
{
int nx = x + dir2[i][0];
int ny = y + dir2[i][1];
if ((nx >= 0 && nx < n && ny >= 0 && ny < m && cal(mpk(ex - sx, ey - sy), mpk(nx - sx, ny - sy)) > 0) || (nx == ex && ny == ey))
{
if (dis[nx][ny] > dis[x][y] + a[nx][ny] + (a[x][y] + a[nx][ny]) * k)
{
dis[nx][ny] = dis[x][y] + a[nx][ny] + (a[x][y] + a[nx][ny]) * k;
if (!vis[nx][ny])
q.push({nx, ny}), vis[nx][ny] = 1;
}
}
}
}
ans += dis[ex][ey];
} void solve()
{
cin >> n >> m;
for (int i = 0; i < n; ++i)
for (int j = 0; j < m; ++j)
cin >> a[i][j];
cin >> sy >> sx >> ey >> ex;
spfa(sx, sy);
swap(sx, ex), swap(sy, ey);
spfa(sx, sy);
cout << fixed << setprecision(2) << ans - a[sx][sy] - a[ex][ey] << endl;
}
signed main(void)
{
Zeoy;
int T = 1;
// cin >> T;
while (T--)
{
solve();
}
return 0;
}

2017GPLT的更多相关文章

随机推荐

  1. SQLSERVER 语句交错引发的死锁研究

    一:背景 1. 讲故事 相信大家在使用 SQLSERVER 的过程中经常会遇到 阻塞 和 死锁,尤其是 死锁,比如下面的输出: (1 row affected) Msg 1205, Level 13, ...

  2. vant组件,picker时间选择,自定义时间选择,实现datePacker,时间选择长期,增加长期选项,用于选择身份证到期时间等...

    vant组件,picker时间选择,自定义时间选择,实现datePacker,时间选择长期,增加长期选项,用于选择身份证到期时间等... 最近项目中有个需求,datePicker选项,需要实现增加一个 ...

  3. 跳板攻击之:ICMP代理转发与反弹shell

    跳板攻击之:ICMP代理转发与反弹shell 郑重声明: 本笔记编写目的只用于安全知识提升,并与更多人共享安全知识,切勿使用笔记中的技术进行违法活动,利用笔记中的技术造成的后果与作者本人无关.倡导维护 ...

  4. 四川九联代工M301H hi3798 mv300 mt7668魔百和 强刷和TTL线刷(救砖)经验分享

    以下都是本次自己操作后的一些经验,不是技术分享,也是看来很多水教程后总结的精华. 四川九联代工M301H hi3798 mv300 mt7668魔百和  一.强刷 1.强刷的教程网上有很多,自己百度. ...

  5. 基于Ubuntu搭建OpenGL开发环境

    1. 引言 笔者这里基于Ubuntu 20.04.3 LTS系统,搭建OpenGL开发环境,主要使用的库有GLFW和GLAD GLFW是一个专门针对OpenGL的C语言库,它提供了一些渲染物体所需的最 ...

  6. Map Inference in the Face of Noise and Disparity代码环境搭建

    1. 引言 地图生成算法网站Mapconstruction by pfoser里可以看到许多关于地图生成算法的介绍,Map Inference in the Face of Noise and Dis ...

  7. 路飞项目使用mysql数据库详细讲解

    目录 一.首先需要彻底删除原有的数据库步骤 二.去官网下载mysql步骤 三.安装mysql数据库步骤 四.一管理员身份进去cmd进行一系列命令启动 五.接下来为路飞项目创建数据库 六.luffy项目 ...

  8. 极速编程体验:VsCode和webstorm插上ChatGPT

    ChatGPT走入了千家万户,而她最适合的用法之一就是进行编程辅助,特别是对一些常规开发,有比较好的引导作用. 很多主流编辑器都有相关的插件支持接入ChatGPT,而VsCode和webstorm是我 ...

  9. 坏消息,new Date()方法在IOS系统中存在null值情况

    背景介绍 笔者最近在开发小程序,发现在使用new Date()函数在电脑模拟器上倒是没什么影响能很好实现效果,但是在我的Iphone上看到的效果跟预想有出入. 图为在电脑微信小程序模拟器的效果图,可以 ...

  10. c++_成员函数回调

    //--------------------------------------------------------------------------- #include <vcl.h> ...