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';
}