HDU 4427 Math Magic (2012年长春现场赛H题)

1.题目描述:点击打开链接

2.解题思路:本题要求寻找k个正整数,它们的和恰好是N,它们的LCM恰好是M的解的个数。可以设置一个三维的dp来解决。用dp(i,j,k)表示选择i个数,它们的和恰好是j,它们的LCM恰好是k的个数。那么答案就是dp(k,n,m)。不过这里介绍一种利用状态压缩思想求解的方法。

通过题意可以发现,N,M的范围都比较小,不超过1000,而1000之内的所有数的不同素因子的种类数目不超过4个,这是因为2*3*5*7<1000,而2*3*5*7*11>1000。考虑到素因子种类数非常少的特点,我们可以考虑状态压缩。设dp(i,j,s)表示选择i个数,它们的和恰好是j,它们的不同素因子(这里考虑的素因子都是它的幂次恰好和M分解后对应的幂次相等的那个素因子)构成的集合为s时的解的个数。可以利用刷表法来求解,刷新公式如下:

dp(i,j+d[i],k|s[i])=dp(i,j+d[i],k|s[i])+dp(i-1,j,k);

上式中,d[i]表示M的第i个约数,s[i]表示第i个约数的“合格”的素因子构成的集合。假设M一共有L种不同的素因子,那么,k个整数的LCM恰好等于M就等价于dp(k,N,2^L-1)。2^L-1就是这L种素因子构成的集合的全集。这样,本题便可以被顺利的解决。

3.代码:

#include<iostream>
#include<algorithm>
#include<cassert>
#include<string>
#include<sstream>
#include<set>
#include<bitset>
#include<vector>
#include<stack>
#include<map>
#include<queue>
#include<deque>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<ctime>
#include<cctype>
#include<functional>
#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std;

#define me(s)  memset(s,0,sizeof(s))
#define rep(i,n) for(int i=0;i<(n);i++)
typedef long long ll;
typedef unsigned int uint;
typedef unsigned long long ull;
typedef pair <int, int> P;

const int MOD=1e9+7;

const int N=1050;

int dp[110][N][1<<4];
int primes[N];
int vis[N];
int idx;

void init() //筛素数
{
    me(vis);
    int m=sqrt(N+0.5);
    for(int i=2;i<=m;i++)
        if(!vis[i])
        for(int j=i*i;j<N;j+=i)
        vis[j]=1;
    for(int i=2;i<N;i++)
        if(!vis[i])
        primes[idx++]=i;
}

int main()
{
    init();
    int n,m,k;
    int num[5],p[5],d[233],type[233]; //p[i]表示M的第i个素因子,num[i]表示该素因子的幂次,d[i]表示M的第i个约数,type[i]表示第i个约数的“合格的”素因子构成的集合
    int l,tot;                        //l表示M一共有l种不同的素因子,tot表示M一共有tot个约数
    while(~scanf("%d%d%d",&n,&m,&k))
    {
        l=0;
        for(int i=0,j=m;primes[i]<=j;i++)//对M进行分解
            if(j%primes[i]==0)
        {
            p[l]=primes[i];
            num[l]=0;
            while(j%primes[i]==0)j/=primes[i],num[l]++;
            l++;
        }
        tot=0;
        for(int i=1;i<=m;i++) //寻找M的所有约数
            if(m%i==0)
        {
            d[tot]=i;
            type[tot]=0;
            int tmp=i,cnt;
            for(int j=0;j<l;j++)
                if(tmp%p[j]==0)
            {
                cnt=0;
                while(tmp%p[j]==0)tmp/=p[j],cnt++;
                if(cnt==num[j])  //如果该约数分解后,某一项的幂次和M对应的幂次相等,说明是一个合法的素因子,加入集合
                    type[tot]|=1<<j;
            }
            tot++;
        }
        int up=1<<l; //up表示M的不同素因子构成的全集
        me(dp);
        for(int i=0;i<tot&&d[i]<=n;i++)
            dp[1][d[i]][type[i]]=1;  //刷新时候需要的基础的解
        for(int i=2;i<=k;i++)
            for(int j=1;j<=n;j++)
            for(int k=0;k<up;k++)//枚举所有集合
            if(dp[i-1][j][k])
            for(int kk=0;kk<tot&&d[kk]+j<=n;kk++)//枚举所有可能的约数,进行刷新
            dp[i][j+d[kk]][k|type[kk]]=( dp[i][j+d[kk]][k|type[kk]]+dp[i-1][j][k])%MOD;
        printf("%d\n",dp[k][n][up-1]);
    }
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-14 05:38:12

HDU 4427 Math Magic (2012年长春现场赛H题)的相关文章

HDU 4815 2013长春现场赛C题

C - Little Tiger vs. Deep Monkey Time Limit:1000MS     Memory Limit:65535KB     64bit IO Format:%I64d & %I64u Submit Status Practice HDU 4815 Description A crowd of little animals is visiting a mysterious laboratory ? The Deep Lab of SYSU. "Are y

HDUOJ-------2493Timer(数学 2008北京现场赛H题)

Timer Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 445    Accepted Submission(s): 90 Problem Description Recently, some archaeologists discovered an ancient relic on a small island in the Pa

HDU 4427 Math Magic(三维dp)

题目大意:给你三个数n,m,k.表示有k个数,他们的和为n,k个数的最小公倍数是m.让你求出符合这个条件的k个数的序列有多少种. 一看以为是个数论题,还尝试这各种分解m,然后进行组合数求情况.但是组合出来的数没法做减法啊... 结果是道dp题目.i,j,k表示到了第i个数此时和为j,最小公倍数为k.已经有了多少种组合方法了,直接向后推就可以了啊.数组太大开不开啊,滚动一下就可以了啊. Math Magic Time Limit: 4000/2000 MS (Java/Others)    Mem

hdu 5538 House Building(长春现场赛——水题)

题目链接:acm.hdu.edu.cn/showproblem.php?pid=5538 House Building Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 262144/262144 K (Java/Others) Total Submission(s): 621    Accepted Submission(s): 398 Problem Description Have you ever played the vid

hdu 4813(2013长春现场赛A题)

把一个字符串分成N个字符串 每个字符串长度为m Sample Input12 5 // n mklmbbileay Sample Outputklmbbileay 1 # include <iostream> 2 # include <cstdio> 3 # include <cstring> 4 # include <algorithm> 5 # include <string> 6 # include <cmath> 7 # in

HDU 5074 Hatsune Miku(2014鞍山赛区现场赛E题)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5074 解题报告:给出一个长度为n的序列,例如a1,a2,a3,a4......an,然后这个序列的美丽值就是socre[a1][a2] + socre[a2][a3] + ..... socre[an-1][an],但是这个序列里面并不是所有的数都是确定的,输入包含一些大于0的数和一些-1,-1表示这个数可以任意,但是要在m的范围内,给出socre[i][j],求这个序列最大的美丽值. 一个二维dp

hdu 4438 第37届ACM/ICPC 天津赛区现场赛H题

题意:Alice和Bob两个人去打猎,有两种(只)猎物老虎和狼: 杀死老虎得分x,狼得分y: 如果两个人都选择同样的猎物,则Alice得分的概率是p,则Bob得分的概率是(1-p): 但是Alice事先知道Bob先选老虎的概率是Q,问Alice得分的期望最大值是 求期望 如果先去打老虎,则会有bob先去打狼和bob去打老虎两种情况,期望相加则是alice去打老虎的期望,然后求打狼的期望,比较大小即可 1 #include<cstdio> 2 #include<iostream> 3

HDU 5119 Happy Matt Friends(2014北京区域赛现场赛H题 裸背包DP)

虽然是一道还是算简单的DP,甚至不用滚动数组也能AC,数据量不算很大. 对于N个数,每个数只存在两个状态,取 和 不取. 容易得出状态转移方程: dp[i][j] = dp[i - 1][j ^ a[i]] + dp[i - 1][j]; dp[i][j] 的意思是,对于数列 中前 i 个数字,使得 XOR 和恰好为 j 的方案数 状态转移方程中的 dp[i - 1][j] 即表示当前这个数字不取, dp[i - 1][j ^ a[i]] 表示当前这个数字要取. 这道题还是要好好理解阿! sou

2014鞍山现场赛H题HDU5077(DFS减枝+打表)

NAND Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 262144/262144 K (Java/Others) Total Submission(s): 65    Accepted Submission(s): 14 Problem Description Xiaoqiang entered the "shortest code" challenge organized by some self-claimed a