A - Alloy
如题
#include <cstdio>
using namespace std;
int main() {
int a, b;
scanf("%d%d", &a, &b);
printf("%s\n", a ? b ? "Alloy" : "Gold" : "Silver");
return 0;
}
B - Weak Password
题目大意:
四位数密码满足以下任一条件被判定为Weak
,否则为Strong
:
- 四位数均相同;
- 从千位至个位依次递增,如
0123
、1234
等,特别地,9012
、8901
、7890
也被是为Weak
。
大致思路:
- 用一个整型变量读入单个四位数
我们会发现,当这个四位数是1111的倍数时,即a % 1111 == 0
时,满足条件一;而对于条件二,除了那三种特殊情况外,均满足a % 1111 == 123 && a < 7000
,即解。
#include <cstdio>
using namespace std;
int main() {
int a;
scanf("%d", &a);
if(!(a % 1111) || (a % 1111 == 123 && a < 7000) || a == 7890 || a == 8901 || a == 9012)
printf("Weak\n");
else printf("Strong\n");
return 0;
}
- 拆分成四个一位数理解
当四个变量分别相等时,满足条件一;条件二(前一个变量加一等于后一个变量)可以通过对10取余实现。
#include <cstdio>
using namespace std;
int main()
{
int a, b, c, d;
scanf("%1d%1d%1d%1d", &a, &b, &c, &d);
if(a == b && b == c && c == d) printf("Weak\n"); //条件一
else if(b == (a + 1) % 10 && c == (b + 1) % 10 && d == (c + 1) % 10) printf("Weak\n"); //条件二
else printf("Strong\n");
return 0;
}
- 按照字符理解
当四个字符分别相等时,满足条件一;条件二理解为b-a==1 || a-b==9
。
#include <cstdio>
#include <cstring>
using namespace std;
int main() {
char s[4];
scanf("%s", s);
bool same = true, step = true;
for(int i = 0; i < 3; i++) {
if (s[i] != s[i + 1]) same = false;
if (((s[i] + 1) % 10) != (s[i + 1] % 10)) step = false;
}
if(same || step) printf("Weak\n");
else printf("Strong\n");
return 0;
}
C - Min Difference
题目大意:
给定两个数组A、B,求|A[i] - B[j]|
的最小值。
大致思路:
首先两两比较的复杂度是O(MN)
,一定会超时,因此要想办法优化一下。
差值会在A[i] > B[j]
和A[i] < B[j]
的交界处产生(被减数越小,减数数越大,差值越小)。这里我们用增大减数的方法求解:将A、B中的元素分别从小到大排列,利用两个从1划到n的指针p、q,当A[p] > B[q]
时,q向后移动;反之,移动p。
#include <cstdio>
#include <cmath>
#include <algorithm>
using namespace std;
int a[200010], b[200010];
int main() {
int n, m;
scanf("%d%d", &n, &m);
for(int i = 1; i <= n; i++)
scanf("%d", &a[i]);
sort(a + 1, a + n + 1);
for(int i = 1; i <= m; i++)
scanf("%d", &b[i]);
sort(b + 1, b + m + 1);
int p = 1, q = 1, ans = abs(a[1] - b[1]);
while(p <= n && q <= m) {
ans = min(ans, abs(a[p] - b[q]));
if(a[p] < b[q]) p++;
else q++;
}
printf("%d\n", ans);
return 0;
}
D - Querying Multiset
题目大意:
初始时容器为空,执行n次操作,每种操作都属于以下三种类型之一:
- 将一个新的整数x添加到容器中;
- 现在容器中的每个数都加x;
- 把容器中最小的数取出来,记录并丢掉(有多个最小数时,只取一个就行)。
要求按照询问顺序输出类型三操作中所记录的数。
大致思路:
这里需要一个能够实现插入、删除元素,有优先级又不自动去重的容器,可以联想到优先队列(priority_queue)和multiset。
- 优先队列虽然能够自定义优先级,但是只能访问到(具有最高优先级的)堆顶元素,不能直接实现类型二中修改数值的功能。因此我们可以利用类似于线段树中的
lazy
标记(把要加的数都记在小本本上,秋后算账)来实现这一操作。
#include <cstdio>
#include <queue>
#define ll long long
using namespace std;
int main() {
ll n;
scanf("%lld", &n);
priority_queue<ll, vector<ll>, greater<ll> > a;
ll Lazy = 0;
for(ll i = 0; i < n; i++) {
int p;
scanf("%d", &p);
if(p == 3) {
printf("%lld\n", Lazy + a.top());
a.pop();
}
else {
ll q;
scanf("%lld", &q);
if(p == 1) a.push(q - Lazy);
else Lazy += q;
}
}
return 0;
}
- 至于multiset,它是
<set>
库中一个非常有用的类型,可以看成一个序列,能够在O(logn)
的时间内完成插入(或删除)一个数,而且他能够时刻保证序列有序,允许存在重复的数(multiset与set最大的区别也在于是否拥有去重功能)。
#include <cstdio>
#include <set>
#define ll long long
using namespace std;
int main() {
ll n;
scanf("%lld", &n);
multiset<ll> st;
ll Lazy = 0;
for(ll i = 0; i < n; i++) {
int p;
scanf("%d", &p);
if(p == 3) {
multiset<ll>::iterator it = st.begin();
printf("%lld\n", (*it) + Lazy);
st.erase(it);
}
else {
ll q;
scanf("%lld", &q);
if(p == 1) st.insert(q - Lazy);
else Lazy += q;
}
}
return 0;
}
E - Safety Journey
题目大意:
有N个原本两两之间直接连通的城市,随着时间的推移,有M条路无法使用,其中第i条路连接着城市U[i]
和城市V[i]
。(有一个全联通的双向图,删掉它的M条边,其中第i条边的端点为U[i]
和V[i]
。)
现在要进行K天的旅行,起点与终点均为城市1,且要求任意相邻的两天都不在同一个城市。(求一个长度为K+1
的序列A(A[0], A[1], ... , A[K]
),要求A[0] = A[K] = 1
且对于对于任意节点满足A[i] != A[i + 1]
。)
输出符合要求的不同的旅行方案数,结果对998244353
取模。对于方案P、Q而言,只要有一个城市不同,就认为这两种方案是不同的。
大致思路:
我们尝试用动态规划解决本题。
设dp[i][j]
表示城镇序列数量(A[0], ... , A[i])
使得A[0] = 0
、A[i] = j
,并且对于任意0 <= i' <= i-1
都满足A[i']
和A[i'+1]
彼此相连。然后dp[0][0] = 1
、dp[0][1] = ... = dp[0][N] = 0
和dp[i+1][j]
就可以表达为
d p [ i + 1 ] [ j ] = ∑ j ′ ∈ S j d p [ i ] [ j ′ ] dp[i+1][j]=\displaystyle\sum_{j'\in S_j}dp[i][j'] dp[i+1][j]=j′∈Sj∑dp[i][j′]
其中S(j)
是j
和j'
间有道路相连的集合。
然而,直接计算需要O(N^2K)
的复杂度,这不太行,所以,我们将表达式转换为
d p [ i + 1 ] [ j ] = ∑ j ′ = 1 N d p [ i ] [ j ′ ] − ∑ j ′ ∈ S j d p [ i ] [ j ′ ] dp[i+1][j]=\displaystyle\sum_{j'=1}^Ndp[i][j']-\displaystyle\sum_{j'\in S_j}dp[i][j'] dp[i+1][j]=j′=1∑Ndp[i][j