Codeforces837D-Round Subset

(有任何问题欢迎留言或私聊 && 欢迎交流讨论哦

题意:传送门

 原题目描述在最下面。
 n个数中选出k个数,使得k个数的乘积末尾的0最多。
 思想和这次蓝桥杯那题差不多orz。当时不会写哇。

思路:

 一个数的末尾0的个数一定等于min(因子2的个数,因子5的个数)

 先预处理出每个数因子2和因子5的个数
dp[i][j] 表示选取了i个数,因子2的个数为j的情况下,因子5的最多个数
 然后注意200个数字因子最多共有200*63个2
 最后枚举使得ans = max(min(dp[k][i], i))

AC代码:

#include<bits/stdc++.h>
#pragma optimize ("-Ofast")
using namespace std;
typedef long long LL;
const int INF = 1e9;
const int N = (int)200+7;
const int M = 64*200;
int n, k;
int dp[N][M+5], k2[N], k5[N];
/*
n个数中选出k个数,使得k个数的乘积末尾的0最多
一个数的末尾0的个数一定等于min(因子2的个数,因子5的个数)
预处理出每个数因子2和因子5的个数
dp[i][j] 表示选取了i个数,因子2的个数为j的情况下,因子5的最多个数
200个数字因子最多共有200*63个2
最后使得ans = max(min(dp[k][i], i))
*/
void init(){
  memset(k2, 0, sizeof(k2));
  memset(k5, 0, sizeof(k5));
  memset(dp, -1, sizeof(dp));
}
int main(){
#ifndef ONLINE_JUDGE
    freopen("E://ADpan//in.in", "r", stdin);
    freopen("E://ADpan//out.out", "w", stdout);  
#endif
  while(~scanf("%d%d", &n, &k)){
    init();
    for(LL i = 1, tmp; i <= n; ++i){
      scanf("%lld", &tmp);
      while(tmp%2 == 0)k2[i]++,tmp/=2;
      while(tmp%5 == 0)k5[i]++,tmp/=5;
    }
    dp[0][0] = 0;
    for(int i = 1; i <= n; ++i){
      for(int j = k; j >= 1; --j){
        for(int t = M; t >= k2[i]; --t){
          if(dp[j-1][t-k2[i]] != -1)
           dp[j][t] = max(dp[j-1][t-k2[i]]+k5[i] , dp[j][t]);
        }
      }
    }
    int ans = 0;
    for(int i = 0; i <= M; ++i){
      ans= max(ans, min(dp[k][i], i));
    }
    printf("%d\n", ans);
  }
  return 0;
}


原题目描述:

这里写图片描述

猜你喜欢

转载自blog.csdn.net/qq_39599067/article/details/81144625