码迷,mamicode.com
首页 > 其他好文 > 详细

BZOJ 3233 Ahoi2013 找硬币 动态规划

时间:2015-06-09 22:06:19      阅读:637      评论:0      收藏:0      [点我收藏+]

标签:bzoj   bzoj3233   动态规划   

题目大意:给定n个数,求一种混合进制使得每个数各个位之和之和最小
fi表示表示最大硬币面值为i时零头部分(即ak mod i部分)的最小硬币数
那么有转移方程:fj=min{fi+nk=1?ak mod ji?}(i|j)
然后ans=min{fi+nk=1?aki?}
时间复杂度O(nmlogm),光荣TLE
优化:ji一定是质数,否则我可以多添加一种硬币而不伤身体(雾
那么我们只需要枚举质数倍数即可
时间复杂度O(nmloglogm),这样就可以过了

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define M 100100
using namespace std;
int n,a[55];
int f[M],ans=0x3f3f3f3f;
int prime[M],tot;
bool not_prime[M];
void Linear_Shaker()
{
    int i,j;
    for(i=2;i<=100000;i++)
    {
        if(!not_prime[i])
            prime[++tot]=i;
        for(j=1;prime[j]*i<=100000;j++)
        {
            not_prime[prime[j]*i]=true;
            if(i%prime[j]==0)
                break;
        }
    }
}
int main()
{
    int i,j,k;
    Linear_Shaker();
    cin>>n;
    for(i=1;i<=n;i++)
        scanf("%d",&a[i]);
    memset(f,0x3f,sizeof f);f[1]=0;
    for(i=1;i<=100000;i++)
    {
        for(j=1;j<=tot&&prime[j]*i<=100000;j++)
        {
            int val=prime[j]*i;
            long long temp=0;
            for(k=1;k<=n;k++)
                temp+=a[k]%val/i;
            if(temp<=0x3f3f3f3f)
                f[val]=min(f[val],f[i]+(int)temp);
        }
        long long temp=f[i];
        for(k=1;k<=n;k++)
            temp+=a[k]/i;
        if(temp<=0x3f3f3f3f)
            ans=min(ans,(int)temp);
    }
    cout<<ans<<endl;
    return 0;
}

BZOJ 3233 Ahoi2013 找硬币 动态规划

标签:bzoj   bzoj3233   动态规划   

原文地址:http://blog.csdn.net/popoqqq/article/details/46430211

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!