Educational Codeforces Round 26 D

Round Subset

题意:给n个数,从中选出k个数,求选出的k个数的乘积结尾的0最多是多少

思路:类似于背包的递推,dp[i][j][k]表示前i个数选j个数含有k个5的方案下2的最大数,第一维用滚动数组优化,由于5^26>1e18,所以第二维开200*26即可 递推式为

dp[i+1][j+1][k+count5[i+1]] = max( dp[ i ] [ j ] [ k ] + count2[ i+1 ], dp[ i+1 ]  [ j+1 ] [ k + count5[ i+1 ] ] );

dp[ i+1 ] [ j ] [ k ] = max( dp[ i ] [ j ] [ k ], dp[ i+1 ] [ j ] [ k ] );

dp初始化为-inf,dp[0][0][0]初始化为0

AC代码:

#include "iostream"
#include "iomanip"
#include "string.h"
#include "stack"
#include "queue"
#include "string"
#include "vector"
#include "set"
#include "map"
#include "algorithm"
#include "stdio.h"
#include "math.h"
#pragma comment(linker, "/STACK:102400000,102400000")
#define bug(x) cout<<x<<" "<<"UUUUU"<<endl;
#define mem(a,x) memset(a,x,sizeof(a))
#define step(x) fixed<< setprecision(x)<<
#define mp(x,y) make_pair(x,y)
#define pb(x) push_back(x)
#define ll long long
#define endl ("
")
#define ft first
#define sd second
#define lrt (rt<<1)
#define rrt (rt<<1|1)
using namespace std;
const long long INF = 1e18+1LL;
const int inf = 1e9+1e8;
const int N=1e5+100;
const ll mod=1e9+7;

///dp[i][j][k]表示前i个数选j个数含有k个5的方案下2的最大数
ll a[205],b[205],c[205],n,k,dp[3][205][205*26];
int main(){
    ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
    cin>>n>>k;
    for(int i=1; i<=n; ++i){
        cin>>a[i];
        for(ll x=a[i]; x%2==0; x/=2,b[i]++);
        for(ll x=a[i]; x%5==0; x/=5,c[i]++);
    }
    mem(dp,-127); dp[0][0][0]=0;
    int cur=0;
    for(int i=0; i<n; ++i){
        for(int j=0; j<=k; ++j){
            for(int t=0; t<=200*26; ++t){
                dp[cur^1][j+1][t+c[i+1]]=max(dp[cur^1][j+1][t+c[i+1]],dp[cur][j][t]+b[i+1]);
                dp[cur^1][j][t]=max(dp[cur^1][j][t],dp[cur][j][t]);
            }
        }
        cur^=1;
    }
    ll ans=0;
    for(ll i=1; i<=200*26; ++i) ans=max(ans,min(i,dp[cur][k][i]));
    cout<<ans;
    return 0;
}
原文地址:https://www.cnblogs.com/max88888888/p/7365150.html