A. Got Any Grapes?
AC代码:
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner cin=new Scanner(System.in);
int x = cin.nextInt();
int y = cin.nextInt();
int z = cin.nextInt();
int a = cin.nextInt();
int b = cin.nextInt();
int c = cin.nextInt();
boolean f = true;
if(a < x){
f = false;
}else{
a -= x;
int d = a + b;
if(d < y){
f = false;
}else{
d -= y;
if(d + c < z){
f = false;
}
}
}
System.out.println(f?"YES":"NO");
cin.close();
}
}
B. Yet Another Array Partitioning Task
题目大意:
对于一个长度为n的数组,将它划分为k个子数组,每个子数组不少于m个元素,子数组中前m大的元素和被称为这一子数组的美丽度,求这k个子数组的美丽度的和。
解题思路(贪心):
就是求这个数组的前k*m大的元素之和。
解题步骤:
- 将数组的值和下标作为pair键值对,放入到vector中排序(按照值的大小排序)
- 将排序好的数组中的前k*m个pair元素放入到一个新的集合vector中,然后按照下标排序
- 输出前k-1组的最后一个下标(如下代码所示)
AC代码:
#include<bits/stdc++.h>
using namespace std;
using LL = long long;
int main(){
// ifstream cin("input.txt");
int n, m, k;
cin >> n >> m >> k;
vector<pair<int, int> >v(n);
for(int i = 0; i < n; i++){
cin >> v[i].first;
v[i].second = i;
}
sort(v.begin(), v.end(), [](pair<int, int>pa, pair<int, int>pb)->bool{
if(pa.first != pb.first)
return pa.first > pb.first;
return pa.second < pb.second;
});
vector<pair<int, int> > v2;
LL cnt = 0;
for(int i = 0; i < k * m; i++){
cnt += v[i].first;
v2.emplace_back(v[i]);
}
sort(v2.begin(), v2.end(), [](pair<int, int>pa,pair<int, int>pb)->bool{
return pa.second < pb.second;
});
cout << cnt << endl;
for(int i = m-1, t = 1; t < k;t++, i += m){
cout << v2[i].second+1 << " ";
}
return 0;
}
C. Trailing Loves (or L’oeufs?)
题目大意:
将n!转化成b进制后,尾部的0有多少个
解题思路(数论):
一个数转化成b进制后尾部的0的数目,就是这个数中bk中的k的个数。
那么我们可以将b分解成素数的乘积,即b=p1a1∗p2a2∗...∗pkak,然后求出最小的b的分解中每个素数pi的n!对应的素数分解中的倍数。n!阶乘中pi的指数的个数为pin+pi2n+...+pirn,其中pir<=n。所以本题最终所求为:min(aipin+pi2n+...+pir)n),1<=i<=k
AC代码:
#include<bits/stdc++.h>
using namespace std;
using LL=unsigned long long ;
int main(){
LL n,b;
cin>>n>>b;
map<LL, LL> M;
LL i = 2;
while(i <= b / i){//此处有坑,当心乘法LL溢出,所以用除法判断
while(b % i == 0){
M[i]++;
b /= i;
}
i++;
}
if(b!=1)M[b]++;
LL gmax = ~0LL;
for(auto p: M){
LL a = 1;
LL cnt = 0;
while(a <= n/p.first){//此处有坑,当心乘法LL溢出,所以用除法判断
a *= p.first;
cnt += n / a;
}
gmax = min(gmax, cnt / p.second);
}
cout << gmax << endl;
return 0;
}
D. Flood Fill
题目大意:
一个长度为n的数组c,每个位置i都有一种颜色c[i],如果连续的一段区间颜色全部相同,则说明是同一块。每次变换一块的颜色算操作一次,求将整个数组变成仅有一种颜色需要操作多少次。
解题思路(动态规划):
设将区间[l, r]变为一种颜色c[l]
的最少变换次数为dp[l][r][0]
,
设将区间[l, r]变为一种颜色c[r]
的最少变换次数为dp[l][r][1]
,
那么则有动态转移方程为:
dp[l-1][r][0] = min(dp[l-1][r][0], dp[l][r][k] + (t != c[l-1]));// 当r > 0
dp[l][r+1][1] = min(dp[l][r+1][1], dp[l][r][k] + (t != c[r+1]));// 当r < n-1
AC代码:
#include<bits/stdc++.h>
using namespace std;
int main(){
//ifstream cin("input.txt");
int n;
cin >> n;
vector<int>c(n);
for(int i = 0; i < n; i++){
cin >> c[i];
}
int dp[n][n][2];
for(int i = 0; i < n; i++){
for(int j = 0; j < n; j++){
if(i == j){
dp[i][j][0] = dp[i][j][1] = 0;
}else{
dp[i][j][0] = dp[i][j][1] = INT_MAX/2;
}
}
}
for(int r = 0; r < n; r++){
for(int l = r; l >= 0; l--){
for(int k = 0; k < 2; k++){
int t = (k?c[r]:c[l]);
if(l)
dp[l-1][r][0] = min(dp[l-1][r][0], dp[l][r][k] + (t != c[l-1]));
if(r < n-1)
dp[l][r+1][1] = min(dp[l][r+1][1], dp[l][r][k] + (t != c[r+1]));
}
}
}
cout << min(dp[0][n-1][0], dp[0][n-1][1]) << endl;
return 0;
}