Atcoder Beginner Contest 208

本文探讨了四个编程问题:A-RollingDice的骰子组合策略,B-FactorialYenCoin的硬币找零算法,C-FairCandyDistribution的糖果公平分配,以及D-ShortestPathQueries2的最短路径计算。通过实例和代码展示了如何在这些场景下运用贪心、排序和动态规划等技巧。
摘要由CSDN通过智能技术生成

A - Rolling Dice

骰子投B次能不能使得总和为A.

很明显,如果A<=B 而且 B<=A*6 那么就一定可以。因为1-6都可以组合出目标值来

#include<bits/stdc++.h>
using namespace std;
int main()
{
    int a,b;
    cin>>a>>b;
    if(a<=b && b<=a*6)
        puts("Yes");
    else 
        cout<<"No";
}

B - Factorial Yen Coin

10种硬币的面值分别是1!,2!…10!

然后问最少用多少枚硬币凑出目标值。

这是标准的贪心题目,先用面值最大的,再用面值小的。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll get(ll x){
    if (x==1)
        return 1;
    return x*get(x-1);
}
int main()
{
    ll p;
    cin>>p;
    vector<ll>a(11);
    for(int i=1;i<=10;i++){
        a[i]=get(i);
    }
    int res=0;
    for(int i=10;i>=1 && p>0;i--){
        int t1=p/a[i];
        if(t1>0){
            res+=t1;
            p-=t1*a[i];
        }
    }
    cout<<res;
}

C - Fair Candy Distribution

一共有N个人标号为ai,然后有K个糖果,进行如下步骤:

当K大于等于N时,每个人都分一个糖果。

否则,分一个糖果给标号为第k小的人。

求最终每个人手里的糖果数量。

根据题目的例子可以看出,最终输出是要按照原来的输入的顺序,所以我们不能直接对原有的数组进行排序,所以选择设一个二维数组,第一个位置放ai,第二个位置放输入时的顺序,那么利用sort排序时,会自动根据第一个位置进行从小到大的排序。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int main()
{
    ll n,k;
    cin>>n>>k;
    vector<vector<ll>>a(n,vector<ll>(2));
    for(int i=0;i<n;i++){
        cin>>a[i][0];
        a[i][1]=i;
    }
    sort(a.begin(),a.end());
    vector<ll>res(n,k/n);
    for(int i=0;i<k%n;i++){
        res[a[i][1]]++;
    }
    for(int i=0;i<n;i++){
        cout<<res[i]<<endl;
    }
}

D - Shortest Path Queries 2

这个题目要求很乱,英文也不好理解。

大体意思就是给定一个N个顶点,M条边的一个有权无向图,然后定义了一个函数,这个函数表示从s节点到t节点走k步的最短距离,同时如果s==t,那么距离就是0.

然后求所有的s、t、k的和。

其实就是用Floyed算法求出每个顶点到其他顶点的最短路径然后求和,但是注意的是这个k因为从1开始,所以有的顶点是无法到达的,此时设置为无穷大,具体在循环中只需要判断是不是无穷大,不是才将距离加入到结果中。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int g[405][405];
ll INF=0x3f3f3f3f;
int n,m;
ll sum;
void Floyed(){
    for(int k=1;k<=n;k++){
        for(int i=1;i<=n;i++){
            for(int j=1;j<=n;j++){
                g[i][j]=min(g[i][j],g[i][k]+g[k][j]);
            }
        }
        for(int i=1;i<=n;i++){
            for(int j=1;j<=n;j++){
                if(g[i][j]<INF)
                    sum+=g[i][j];
            }
        }
    }
}
int main()
{
    cin>>n>>m;
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++){
            if(i!=j)
                g[i][j]=INF;
        }
    }
    for(int i=0;i<m;i++){
        int a,b,v;
        cin>>a>>b>>v;
        g[a][b]=min(g[a][b],v);
    }
    Floyed();
    cout<<sum;
}

E-Digit Products

题目要求是小于正整数N的各位乘积小于k的正整数的个数。

记忆化递归搜索

题目也就是两个条件:

1、X<N

2、各位乘积<K

分为三种情况:

1.当n为0时,如果k为0,则答案为1,如果k大于0,则答案为0

2.当n的最后一位为0(n>1)时,那么条件1就转化为 X<n/10 ,而条件2各种情况下都满足。

例如 当 n = 1230时,那么 从0010开始 到 1230结束,这一共123个数字都满足条件,而很显然,因为最后一位为0,所以各位的乘积一定为0,那么因为k是正整数,所以一定满足小于k。

3.当n的最后一位为1-9,设为y,则 n = 10x + y,其中10x是情况2,则条件1变成了X<(n-y)/10, 则k变成了k/y

代码也是借鉴的日语端的官方题解,还有一种方式是数位DP,记忆化搜索好理解一些,代码也短。

#include<bits/stdc++.h>
using namespace std;
using ll = long long;

map<pair<ll, ll>, ll> memo;
ll dp(ll n, ll k) {
  if (memo.count({n, k})) return memo[{n, k}];
  ll res = (k > 0) + n/10;
  for (ll y = 1; y < 10 && y <= n; y++) res += dp((n-y)/10, k/y);
  return memo[{n, k}] = res;
} 

int main() {
  ll n, k; cin >> n >> k;
  cout << (dp(n, k) - 1) << '\n';
}

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值