首页 > 代码库 > Educational Codeforces Round 26-D. Round Subset

Educational Codeforces Round 26-D. Round Subset

题目大意:给你n个数字(小于1e18),从n个数中取k个数字相乘,使其后缀0最多,问你后缀0最多是多少。

 

知道得用三维的dp[ i ] [ j ] [ k ]  第一维表示用到第 i 个数为止,j 表示从中选 j 个数,想了好久也不知道

第三维是什么,我想不到怎么总结当前状况相乘之后 0 的个数QAQ。

 

思路:其实后面0的个数就是相乘之后有多少个10,10可以分解成 2 * 5,这样我们只要统计每个数字中

有多少个2的因子和5的因子就好了。dp [ i ][ j ][ k ]表示,在(1 - i )之间取 j 个数,5因子的数量为 k  的

情况,2的因子的最大个数。c1[ i ] 表示第 i 个数的因子中有多少个 2 ,c2[ i ]表示有多少个5

状态转移方程 dp[ i ][ j ][ k ]=max(dp[ i ][ j ][ k ] , dp[ i -1 ][ j - 1][ k-c2[ i ] ] + c1[ i ]);    dp[ i ][ j ][ k ]=max( dp[ i ][ j ][ k ] , dp[ i - 1 ][ j ][ k ] )。

还需要注意一点要用滚动数组,不然会MLE。

技术分享
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int inf=0x3f3f3f3f;
int n,k,c1[205],c2[205],dp[2][205][5001];
ll a[205];
void work(ll x,int id)
{
    ll y=x;
    int cnt=0;
    while(!(y&1))
    {
        cnt++;
        y>>=1;
    }
    c1[id]=cnt;
    cnt=0;
    while(x%5==0)
    {
        cnt++;
        x/=5;
    }
    c2[id]=cnt;
}
int main()
{
    cin>>n>>k;
    memset(dp,-1,sizeof(dp));
    for(int i=1;i<=n;i++)
    {
        scanf("%I64d",&a[i]);
        work(a[i],i);
    }
    for(int i=0;i<=1;i++)for(int j=0;j<k;j++)for(int u=0;u<=5000;u++) dp[i&1][j][u]=-inf;
    dp[0][0][0]=0;
    for(int i=1;i<=n;i++)
    {
        for(int u=0;u<=k;u++)
        {
            for(int j=0;j<=5000;j++) dp[i&1][u][j]=-inf;
        }
        for(int u=0;u<=k;u++)
        {
            for(int j=0;j<=5000;j++)
            {
                if(j-c2[i]>=0 && u-1>=0) dp[i&1][u][j]=max(dp[i&1][u][j],c1[i]+dp[(i+1)&1][u-1][j-c2[i]]);
                dp[i&1][u][j]=max(dp[i&1][u][j],dp[(i+1)&1][u][j]);
            }
        }
    }
    int mx=0;
    for(int i=0;i<=5000;i++) mx=max(mx,min(i,dp[n&1][k][i]));
    cout<<mx<<endl;
    return 0;
}
View Code

 

Educational Codeforces Round 26-D. Round Subset