atcoder ABC405 A-E 题解

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;
}
 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值