类计数类DP(其实就是但是懒得往里面挪了....)

一:结合数学知识(废话)vjudge

2021级DP题单 - Virtual Judge (vjudge.net)

就是给你n个数,选出k个*起来

让末尾0个数最多

思路:

一开始找数和数之间的规律,后来找蒙了

想:怎么*出0,质因数分解,只有2*5有0(所有质数)

所以我只需要统计每个数分解出的2和5个数

一一匹配最大时结果最大

怎么选数?

DP

dp[i][j][k]:前i个数选了j个,分解出k个5,最多分解的2的个数//为什么是最多,不应该刚好匹配吗(宁多不少) 
max(dp[i-1][j][k],dp[i-1][j-1][k-div5[i]]+div2[i])
//这个数选或者不选
优化:1.空间不够,滚动数组优化
    2.k这一位5比2好(5更少)

 

const int WR=1001000;ll INF=1e18;
int n,k;
ll A[210],B[210];
int d5[210],d2[210];
int dp[210][6000],tmp[210][6000];
int tot_5;
inline void get2_5(int nd,ll x)
{
    while(x!=0&&x%2==0)
    {
        d2[nd]++;
        x/=2;
    }
    while(x!=0&&x%5==0)
    {
        d5[nd]++;
        x/=5;
    }
    tot_5+=d5[nd];
}//18*200
int main()
{
//    freopen("makeans.txt","r",stdin);
//    freopen("fire.out","w",stdout);
    n=re();k=re();
    _f(i,1,n)
    {
        scanf("%I64d",&A[i]);
        get2_5(i,A[i]);
    //    chu("5:%d 2:%d\n",d5[i],d2[i]);
    }
    memset(dp,-0x3f,sizeof(dp));//不存在的状态也要考虑进去 
    dp[1][d5[1]]=d2[1];//第一个初始化一下 ,如果第一个数不选呢
    dp[0][0]=0; 
    for(int i=2;i<=n;i++)//前i个数 
    {
        //chu("round:%d\n",i);
        memcpy(tmp,dp,sizeof(dp));
        for(int j=1;j<=k;j++)//选j个 
        {
            for(int o=0;o<=tot_5;o++)
            {
                dp[j][o]=tmp[j][o];
            //    chu("不选:dp[%d][%d]:%d\n",j,o,dp[j][o]);
                if(j-1>=0&&(o-d5[i])>=0)dp[j][o]=max(tmp[j][o],tmp[j-1][o-d5[i]]+d2[i]);    
            //    chu("选:(如果更优):%d\n",dp[j][o]);
            }    
        } 
    }
    int maxans=0;
    //从dp[k]里面选
    _f(i,0,tot_5)
    {
    //    chu("dp[%d][%d]:%d\n",k,i,dp[k][i]);
        int minx=min(dp[k][i],i);
        maxans=max(minx,maxans);
     } 
     chu("%d",maxans);
    
    return 0;
}
/*
上午是DP专题
下午复习一下图论 
5 3
15 16 3 25 9

3 2
50 4 20


 
*/

 二:多维度(数据范围足够小)POJ2279

蓝书DP

int lim[6];
int dp[32][32][32][32][32];
int main()
{
//    freopen("makeans.txt","r",stdin);
//    freopen("fire.out","w",stdout);
    int n=re(),k=re();
    _f(i,1,k)lim[i]=re();
    dp[0][0][0][0][0]=1;
    for(int i=0;i<=lim[1];i++)//第一排 
    for(int j=0;j<=lim[2];j++)
    for(int k=0;k<=lim[3];k++)
    for(int m=0;m<=lim[4];m++)
    for(int l=0;l<=lim[5];l++)//第5排 
    {
        if(i+1<=lim[1])dp[i+1][j][k][m][l]+=dp[i][j][k][m][l];
        if(j+1<=lim[2]&&j<i)dp[i][j+1][k][m][l]+=dp[i][j][k][m][l];
        if(k+1<=lim[3]&&k<j)dp[i][j][k+1][m][l]+=dp[i][j][k][m][l];
        if(m+1<=lim[4]&&m<k)dp[i][j][k][m+1][l]+=dp[i][j][k][m][l];
        if(l+1<=lim[5]&&l<m)dp[i][j][k][m][l+1]+=dp[i][j][k][m][l];
    }
    chu("%d",dp[lim[1]][lim[2]][lim[3]][lim[4]][lim[5]]);
    return 0;
}

 

posted on 2022-06-08 16:49  HZOI-曹蓉  阅读(46)  评论(0)    收藏  举报