一场掉分的 ABC /kk
在花了 10 10 10 分钟看完前 4 4 4 题后,选择了赛场上大部分人使用的:先开 D,再按顺序做 A、B、C。(打题的时候才发现应该先开 C 的 QwQ)
但却因为 CSP-S 神秘的太空射线使得自身膨胀,结果 E 想复杂 × 2 \times \ 2 × 2,当场去世。
都是因为 CSP-S,不是我的错
题目大意:
你需要把 x x x 转换成一个两位的 16 16 16 进制数,若不足两位则加上前导 0 0 0。
解法分析:
此题考查人们对输出语句的熟悉程度。
题目解法不多说,直接上代码。
AC Code:
# include
using namespace std;
# define ll long long
# define lf double
# define GO(i,a,b) for(ll i = a; i <= b; i ++)
# define RO(i,b,a) for(ll i = b; i >= a; i --)
# define FO(i,u,head,e) for(int i = head[u]; i; i = e[i].next)
# define CI const int
# define pii pair<int,int>
# define MP(a,b) make_pair(a, b)
# define PB(x) push_back(x)
# define mem(a,x) memset(a, x, sizeof a)
# define F first
# define S second
int n;
int main(){
scanf("%d", &n);
printf("%02llX", n);
return 0;
}
题目大意:
给你 n n n 个数组,第 i i i 个数组大小为 k i k_i ki,再有 q q q 次询问,每次问你第 x x x 个数组的第 y y y 项是什么。
解法分析:
说句闲话,vector 是个好东西。
这道题显然需要动态大小的数组,那就非 vector 莫属了。
AC Code:
# include
using namespace std;
# define ll long long
# define lf double
# define GO(i,a,b) for(ll i = a; i <= b; i ++)
# define RO(i,b,a) for(ll i = b; i >= a; i --)
# define FO(i,u,head,e) for(int i = head[u]; i; i = e[i].next)
# define CI const int
# define pii pair<int,int>
# define MP(a,b) make_pair(a, b)
# define PB(x) push_back(x)
# define mem(a,x) memset(a, x, sizeof a)
# define F first
# define S second
CI maxn = 2e5 + 7;
int n, q;
int l;
vector <int> a[maxn];
int x, y;
int main(){
cin >> n >> q;
GO (i, 1, n){
scanf("%d", &l);
GO (j, 1, l){
int p;
scanf("%d", &p);
a[i].push_back(p);
}
}
while (q --){
scanf("%d %d", &x, &y);
printf("%d\n", a[x][y - 1]);
}
return 0;
}
题目大意:
高桥有 n n n 本书,第 i i i 本编号为 a i a_i ai。他可以不停的卖 2 2 2 本书获得一本任意编号的书,但当剩下的书不到 2 2 2 本时就不能这样了。现在高桥想要从编号为 1 1 1 的书开始读,看完一本就看下一个编号的书,如果没有就不能看了。高桥想尽量多的看书,请计算高桥最多可以看多少本书。
解法分析:
有两种做法,这里只讲二分。
这道题说到了最多
,就想到了二分。考虑当现在二分到了 m i d mid mid,那么:
当你将所有可以买的书卖掉后,看能不能达到期望的数量即可。
AC Code:
# include
using namespace std;
# define ll long long
# define lf double
# define GO(i,a,b) for(ll i = a; i <= b; i ++)
# define RO(i,b,a) for(ll i = b; i >= a; i --)
# define FO(i,u,head,e) for(int i = head[u]; i; i = e[i].next)
# define CI const int
# define pii pair<int,int>
# define MP(a,b) make_pair(a, b)
# define PB(x) push_back(x)
# define mem(a,x) memset(a, x, sizeof a)
# define F first
# define S second
CI maxn = 3e5 + 7;
int n, m;
int a[maxn];
bool check(int mid){
int res = 0;
GO (i, 1, m)
res += (a[i] <= mid);
return (mid - res) * 2 <= (n - res);
}
int main(){
cin >> n;
GO (i, 1, n)
scanf("%d", &a[i]);
sort(a + 1, a + n + 1);
m = 1;
GO (i, 2, n)
if (a[i] != a[i - 1])
a[++ m] = a[i];
int l = 0, r = 1e9;
int ans = 0;
while (l <= r){
int mid = (l + r) >> 1;
if (check(mid)){
ans = mid;
l = mid + 1;
}
else r = mid - 1;
}
cout << ans;
return 0;
}
题目大意:
一共有 n n n 张牌,每一面都写着一个整数。卡 i i i ( 1 ≤ i ≤ n 1≤i≤n 1≤i≤n)前面写着整数 a i a_i ai,后面写着整数 b i b_i bi。
你可以选择是否放置每张卡片的正面或背面可见。
确定是否可以调整卡片的正反面,使得可见整数的和恰好等于 s s s ,如果可能的话,找到卡片的位置来实现这一点。
解法分析:
这是一道一眼盯真的题。这道题目长得就像个 DP,那就设 f i , j f_{i,j} fi,j 为 前i个数和是否能凑成j
,转移方程就是 f i , j = f i − 1 , j − a i ∣ f i − 1 , j − b i f_{i,j}=f_{i-1,j-a_i} | f_{i - 1, j - b_i} fi,j=fi−1,j−ai∣fi−1,j−bi 。
又说这道题需要输出路径,这就是一个经典的路径还原了。设 w i , j w_{i,j} wi,j 为计算 f i , j f_{i,j} fi,j 时做出的选择,然后从后往前递归输出即可。
AC Code:
# include
using namespace std;
# define ll long long
# define lf double
# define GO(i,a,b) for(ll i = a; i <= b; i ++)
# define RO(i,b,a) for(ll i = b; i >= a; i --)
# define FO(i,u,head,e) for(int i = head[u]; i; i = e[i].next)
# define CI const int
# define pii pair<int,int>
# define MP(a,b) make_pair(a, b)
# define PB(x) push_back(x)
# define mem(a,x) memset(a, x, sizeof a)
# define F first
# define S second
CI maxn = 107;
int n, s;
int a[maxn], b[maxn];
bool f[maxn][10007];
char w[maxn][10007];
void out(int n, int s){
if (n == 0)
return ;
out(n - 1, s - (w[n][s] == 'H' ? a[n] : b[n]));
printf("%c", w[n][s]);
}
int main(){
cin >> n >> s;
GO (i, 1, n)
scanf("%d %d", &a[i], &b[i]);
f[0][0] = true;
GO (i, 1, n){
GO (j, 0, s){
f[i][j] = max <bool> ((j >= a[i] ? f[i - 1][j - a[i]] : 0), (j >= b[i] ? f[i - 1][j - b[i]] : 0));
if (j >= a[i] && f[i][j] == f[i - 1][j - a[i]])
w[i][j] = 'H';
else if (j >= b[i] && f[i][j] == f[i - 1][j - b[i]])
w[i][j] = 'T';
else
w[i][j] = 'I';
}
}
printf(f[n][s] ? "Yes\n" : "No\n");
if (f[n][s]) out(n, s);
return 0;
}
题目大意:
有一个有向图, 有 N N N 个编号为 1 , … , N 1,\dots,N 1,…,N 的点和 M M M 条编号为 1 , … , M 1,\dots,M 1,…,M 的路。
第 i i i 条路从 A i A_i Ai 到 B i B_i Bi,长度是 C i C_i Ci。
给定长度为 K K K 的序列 E E E ,由 1 1 1 和 m m m 之间的整数组成。从城镇 1 1 1 到城镇 N N N 的道路被称为好路径,如果:
按照路径中使用的顺序排列的道路编号序列是 E E E 的子序列。
找出一条好的路径所使用的道路长度的最小和。
解法分析:
赛场上想复杂了很多次,一直以为要用 Dijsktra 来做,但其实不然。题目中说一定要按照顺序来走(构成子序列),从另一方面来看,这是在帮我们建图。因为我们只能用 E E E 中的边,还要按顺序使用,则不会出现编号靠后的边比编号靠前的边先走的情况,这就满足了 DP 的无后效性。而 DP 的另外两个性质也是显而易见的满足,于是这道题思路就出来了:设 f i f_i fi 为走到 i i i 的最短路,则按顺序遍历 E E E 的每一条边,每次更新就是 f v = min ( f v , f u + w ) f_v = \min(f_v, f_u + w) fv=min(fv,fu+w),最后输出 f n f_n fn 即可。
AC Code:
# include
using namespace std;
# define ll long long
# define lf double
# define GO(i,a,b) for(ll i = a; i <= b; i ++)
# define RO(i,b,a) for(ll i = b; i >= a; i --)
# define FO(i,u,head,e) for(int i = head[u]; i; i = e[i].next)
# define CI const int
# define pii pair<int,int>
# define MP(a,b) make_pair(a, b)
# define PB(x) push_back(x)
# define mem(a,x) memset(a, x, sizeof a)
# define F first
# define S second
CI maxn = 2e5 + 7;
int n, m, k;
int u[maxn], v[maxn], w[maxn];
int a, b;
ll dis[maxn];
int main(){
cin >> n >> m >> k;
GO (i, 1, n)
dis[i] = 2e18;
GO (i, 1, m)
scanf("%d %d %d", &u[i], &v[i], &w[i]);
dis[1] = 0;
GO (i, 1, k){
scanf("%d", &a);
dis[v[a]] = min <ll> (dis[v[a]], dis[u[a]] + w[a]);
}
cout << (dis[n] == 2e18 ? -1 : dis[n]);
return 0;
}