A - Is it rated?
题意分析
分类讨论:
-
[1600,2999] 之间的分数,在匹配 x=1 时,输出 Yes。
-
[1200,2399] 之间的分数,在匹配 x=2 时,输出 Yes。
-
交叉的范围 [1699,2399] 匹配两者都输出 Yes,其他皆输出 No。
标程
#include <bits/stdc++.h>
using namespace std;
int r, x;
int main(){
cin >> r >> x;
if (r >= 1600 and r <= 2999 and x == 1) cout << "Yes" << endl;
else if (r >= 1200 and r <= 2399 and x == 2) cout << "Yes" << endl;
else cout << "No" << endl;
return 0;
}
B - Not All
题意分析
题目给的数据范围中,给出条件 1≤Ai≤M ,因此可知只要当输入的新数字的数量到达 M 个,即表示数组已经存在 [1,M] 之间的所有整数,那么删除最近输入的数字及后面的数字即可。
标程
#include <bits/stdc++.h>
using namespace std;
int n, m, cnt, a, b[105];
int main(){
cin >> n >> m;
for (int i = 1; i <= n; i++){
cin >> a;
b[a]++;
if (b[a] == 1) cnt++; //新数字增加
if (cnt == m){ //新数字够 m 个
cout << n-(i-1);
return 0;
}
}
cout << 0 << endl;
return 0;
}
C - Sum of Product
题意分析
数学题,求和式子我们用 a,b,c,d 四个数展开,可以表达为:
a∗b+a∗c+a∗d+b∗c+b∗d+c∗d
=a∗(b+c+d)+b∗(c+d)+c∗d
由上式可知,可以初始 sum=a+b+c+d,随后让 sum−a,并累加 (sum−a)∗a 的值,即可得到答案。
标程
#include <bits/stdc++.h>
using namespace std;
long long n, a[300005], sum;
int main() {
cin >> n;
for (int i = 1; i <= n; i++){
cin >> a[i];
sum += a[i];
}
long long ans = 0;
for (int i = 1; i <= n; i++){
sum -= a[i]; //先减再算
ans += sum* a[i];
}
cout << ans << endl;
return 0;
}
D - Escape Route
题意分析
所有能通行的点,都要寻找到一个通往出口的最近路线。显然,我们从出口出发,做BFS,最先遇到的点,就是距离出口最近的点。
在确定了方法后,还需要解决以下两个问题:
1、多个出口,这个问题比较好解决,只要在最初输入的时候,把所有的出口放入队列即可,这样所有点都会去找到距离自身最近的出口。
2、路径如何标识,在BFS中,我们会建立方向数组,如果从出口出发,往上 可以找到一个最近的点 a,那么从点 a 出发去最近的出口,就是 往下 ,即反向设立箭头。
标程
#include <bits/stdc++.h>
using namespace std;
int n, m;
char mat[1005][1005];
struct node{
int x, y;
};
queue<node>q;
void bfs(){
int nxt[4][2] = {0,1,1,0,0,-1,-1,0}; //方向数组
while(!q.empty()){
node t = q.front();
q.pop();
for (int i = 0; i <= 3; i++){
int tx = t.x + nxt[i][0];
int ty = t.y + nxt[i][1];
if (mat[tx][ty] == '.'){ //可通行点
//i==0是(0,1)即往右找到通行点,那么通行点往左找到出口,以下判断相同
if (i == 0) mat[tx][ty] = '<';
else if (i == 1) mat[tx][ty] = '^';
else if (i == 2) mat[tx][ty] = '>';
else mat[tx][ty] = 'v';
q.push((node){tx,ty});
}
}
}
}
int main() {
cin >> n >> m;
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++){
cin >> mat[i][j];
if (mat[i][j] == 'E') q.push((node){i,j});//把所有出口入队
}
bfs();
for (int i = 1; i <= n; i++){
for (int j = 1; j <= m; j++)
cout << mat[i][j];
cout << endl;
}
return 0;
}
E - Fruit Lineup
题意分析
本题只要分析出所有的排列组合方式,那么代入逆元模版就可以完成。
由于苹果在题目中的限制最多,所以我们可以考虑从苹果入手,先把 a 个苹果放完。
苹果必须放在香蕉和葡萄的左边,但可以和橘子混放,因此在所有的 a+b+c+d 个位置中,苹果可以选择 [1,a+b] 的位置任意放置,也就时说,最后一个苹果放置的位置在 [a,a+b] 之间。假设最后一个苹果放的位置为 i,剩余的苹果的放置方法有 Ci−1a−1 种。
在确定了苹果的位置后,我们可以确定的就是香蕉所在的位置,只要放在苹果的后面即可,最后一个苹果在 i 位置,那么香蕉能够选择的位置有 a+b+c+d−i。即有 Ca+b+c+d−ic 种可能。
在苹果和香蕉的位置确定后,橘子必须在葡萄之前,所有橘子和葡萄便是从前往后按顺序放置,不会增加更多的可能性。
在完成排列后,代入逆元模版。
我们在分析的时候,也可以考虑从橘子和香蕉入手,就是 a+b 个位置中,除了 a 个苹果和橘子外,还能能够分配给香蕉多少个位置,因为香蕉和橘子可以混合。设可以分给香蕉 i 个位置,那么分给橘子的位置就是 a+b−i 个,即有 b−i 个橘子可以放入在 a+b−i 的位置中,即 Ca+b−i−1b−i 种情况。那么香蕉的选择就是 Cc+d+ic 种。
标程
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int mod = 998244353;
int a, b, c, d;
int fac[4000005], inv[4000005];
int Inv(int a, int b){
int ans = 1;
while(b){
if (b & 1){
ans = (ans*a)%mod;
}
b >>= 1;
a = a*a%mod;
}
return ans;
}
int C(int x, int y){
if (y > x) return 0;
if (y == x) return 1;
int ans = fac[x];
ans = (ans*inv[x-y])%mod*inv[y]%mod;
return ans;
}
signed main(){
cin >> a >> b >> c >>d;
int n = 4e6;
fac[1] = 1;
for(int i = 2; i <= n+1; i++){
fac[i] = fac[i - 1] * i;
fac[i] %= mod;
}
inv[n + 1] = Inv(fac[n + 1], mod - 2);
for(int i = n; i >= 0; i--){
inv[i] = inv[i + 1] * (i + 1) % mod;
}
int ans = 0;
for(int i = a; i <= a+b; i++){
ans = (ans + C(i-1, a-1) * C(a+b+c+d - i, c) % mod) % mod;
}
//for (int i = 0; i <= b; i++){ //方法二
// ans = (ans + C(a+b-i-1, b-i) * C(c+d+i, c) % mod) % mod;
//}
cout << ans << endl;
return 0;
}