1. 程式人生 > >HDU4427Math Magic (dp+滾動陣列)

HDU4427Math Magic (dp+滾動陣列)

題目連結:

題意:

求選定k個數,k個數的和為n,最小公倍數是m的方案數,最後的結果mod 1000000007;

分析:

狀態轉移很好找,難的是自己去實現優化。

狀態轉移方程為 : dp[i+1][s+k][lcm(l,k)]+=dp[i][s][l];

第一維代表的是有多少個數,第二維代表的是這些數的和,第三維代表的是這些數的最小公倍數

因為開不了那麼大的陣列,因此我們要用滾動陣列,詳細請見註釋。

程式碼如下:

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
using namespace std;

const int mod = 1000000007;

const int maxn = 1005;

inline int gcd(int a,int b)
{
    if(b) return gcd(b,a%b);
    return a;
}

int dp[2][maxn][maxn];
int fac[1000];
int lcm[maxn][maxn];

void init()//預處理1~1000內的任意兩個數的最小公倍數
{
    for(int i=1;i<maxn;i++)
        for(int j=i;j<maxn;j++)
            lcm[i][j]=lcm[j][i]=i*j/gcd(i,j);
}

int main()
{
    init();
    int n,m,k;
    while(~scanf("%d%d%d",&n,&m,&k)){
        memset(dp,0,sizeof(dp));
        int tmp = m, cnt=0,v=0;
        memset(dp,0,sizeof dp);
        for(int i = 1; i<=m; i++)//預處理出m的所有約數,這k個數一定是在m的約數裡面選的
            if(m%i==0) fac[cnt++]=i;
        for(int i=0; i<cnt; i++)//初始化
            dp[v][fac[i]][fac[i]]=1;
        for(int i=1; i<k; i++) //列舉長度
        {
            memset(dp[v^1],0,sizeof(dp[v^1]));
            for(int j=i; j<n; j++) //列舉sum
            {
                for(int p=0; p<cnt; p++) //列舉上一個狀態的公倍數
                {
                    int mul=fac[p];
                    if(!dp[v][j][mul])
                        continue;
                    for(int q=0; q<cnt; q++) //列舉因子
                    {
                        int tt=j+fac[q];//計算當前狀態的和
                        if(tt>n)
                            break;
                        int t = lcm[mul][fac[q]];//當前狀態的最小公倍數
                        dp[v^1][tt][t]+=dp[v][j][mul];//當前狀態等於之前所有可以達到這個狀態的狀態的和
                        dp[v^1][tt][t]%=mod;
                    }
                }
            }
            v^=1;
        }
        printf("%d\n",dp[v][n][m]);
    }
    return 0;
}


相關推薦

HDU4427Math Magic (dp+滾動陣列)

題目連結: 題意: 求選定k個數,k個數的和為n,最小公倍數是m的方案數,最後的結果mod 1000000007; 分析: 狀態轉移很好找,難的是自己去實現優化。 狀態轉移方程為 : dp[i+

POJ-3666 Making the Grade 【動態規劃DP+滾動陣列

題目傳送門 題目:輸入n個數,第i個數字的值為a[i],把第i個數變為j的代價為a[i]-j的絕對值,求把這n個數組成的數列變成單調數列的最小代價。 題解:dp[i][j]表示前i個數最大值為b[j]時的最小代價,即第i個數在總數列中的值為第j小的時候的最小代價。 動態轉移方程:dp

【Codeforces Round #517 (Div. 2, based on Technocup 2019 Elimination Round 2) D. Minimum path】dp+滾動陣列

D. Minimum path 題意 給你一個字元矩陣,起點在左上角,每次可以向右或者向下走,可以改變這個字元矩陣中的k個字元,是這個路徑構成的字串字典序最小。 做法 由於可以改變k個字元,那麼肯定是找到一條路徑,前面至少有k項為a, 後面按照字典序選擇路徑就可以。 所

HDU 1024 簡單dp 滾動陣列

  要求:n個正陣列成的序列,整數範圍-32768 ≤ S ≤ 32767,1 ≤ n ≤ 1,000,000,挑出m個無交集的連續子序列使這些序列和最大,並輸出最大值。 方法:二維dp、滾動陣列降維。 1.dp[i][j]表示第一個數到下標為j的數挑出i個連續子序列組成的最大

poj1159 Palindrome (簡單dp&&滾動陣列

連結: 題意: 至少增添多少個字元可以使原字串變成迴文串 思路: 原字串反轉,求最長公共子序列長度,剩餘的長度就是需要加的字元數 這裡用到了滾動陣列,因為該次的dp其實只取決去前一次的dp

牛客訓練賽36 B題(dp滾動陣列)

2019年第一次比賽,遭逢大敗。。。都不忍心看自己的排名,第一題一直在想該怎麼去優化。發現並不用,直接暴力過。。。心態炸了,第二題是dp題,一開始想到了增加維度以獲得更多資訊,還好死不死的用疲勞度作為第二維。。。結果陣列變成400*81000那麼大。。。一直在推狀態轉移方程還推不出來。。。看了題

POJ 1159 DP+滾動陣列

Palindrome Time Limit: 3000MS Memory Limit: 65536K Total Submissions: 57568 Accepted: 19962 Description A palindrom

hihocoder#1044狀態壓縮dp+滾動陣列

//20ms 0#include<iostream> #include <string.h> #include <stdio.h> using namespace std; #define MAXN 1500 int N,M,Q; i

LeetCode--Best Time to Buy and Sell Stock IV(DP + 滾動陣列

題意:已知第1天、第2天......第N天的股票價格,每天只能進行一次買或者賣,且規定手裡的股票賣出之前不能買進新的股票,問在最多進行K次交易的情況下,採用最優方案淨利潤能有多少。 分析: 1、設j天完成不超過i次交易能得到的最大收益是f(i,j),顯然f(0,0) =

noip 2015 子串(dp+滾動陣列)

 題目大意:給定兩個字串A,B(都是由a,b組成)(長度分別為n,m);你可以在字串A中任擷取k個字串按擷取順序組成字串B,問能擷取的方案數 動態規劃; s[i][j][k]:字串A正要處理第i項了,陣列B匹配正要第j項,已經截取了k個字串,總方案數; f[i][j][

HDU 4576(概率DP+滾動陣列

Michael has a telecontrol robot. One day he put the robot on a loop with n cells. The cells are numbered from 1 to n clockwise.  At first the robot is i

Playing games —— 基本dp+滾動陣列

題目描述 Niuniu likes playing games. He has n piles of stones. The i-th pile has ai stones. He wants to play with his good friend,

POJ1159迴文字串(DP+滾動陣列

題目的大概意思就是給你一個字串,讓你在任意位置新增任意字元讓它變成一個迴文字串,求最少新增的字元數。 這是一道典型的DP,總體思路就是把逆串搞出來,兩個字串求出一個最大公共子序列的長度,然後拿n減去這

最大子段-n上找m個子段的和為最大-動態規劃-二維dp+滾動陣列dp優化

1.二維dp dp[i][j]代表的是j長度上找到i段,使得i段和最大。(其中最後一段的最後一位一定要是a[j],這句話不理解的可以看看http://blog.csdn.net/qq_36523667/article/details/78598426) 這時最後一段分為兩

1024 Max Sum Plus Plus(DP + 滾動陣列

題目大意:求m個不相交區間的最大和 解題思路:這題是參考別人的,傳送門 再自己組織一下,用dp[i][j]表示前j個數組組成了i個不相交區間的最大和,其中第j個數字一定在某個區間內 那現在要決策的是,第j個數組是在和別的陣列成了一個區間,還是自己獨立成了一

HDU 4427 Math Magicdp+優化+滾動陣列】【好題】

Yesterday, my teacher taught us about math: +, -, *, /, GCD, LCM... As you know, LCM (Least common multiple) of two positive numbers can be solved easily

poj 2663 Tri Tiling (狀壓dp+多米諾骨牌問題+滾動陣列反思)

本來直接一波狀壓dpAC的 #include<cstdio> #include<cstring> #include<algorithm> #define REP(i

Happy Matt Friends(利用滾動陣列優化陣列空間的DP)

Happy Matt Friends Time Limit: 6000/6000 MS (Java/Others)    Memory Limit: 510000/510000 K (Java/Others) Total Submission(s): 5492    A

滾動陣列】【狀壓DP】NOI2001炮兵陣地

題目描述 司令部的將軍們打算在N*M的網格地圖上部署他們的炮兵部隊。一個N*M的地圖由N行M列組成,地圖的每一格可能是山地(用“H” 表示),也可能是平原(用“P”表示),如下圖。在每一格平原地形上最多可以佈置一支炮兵部隊(山地上不能夠部署炮兵部隊);一支炮兵部隊在地圖上的攻擊範圍

【poj 1159】 Palindrome DP(類最長公共子序列)+滾動陣列

Palindrome Time Limit: 3000MS Memory Limit: 65536K Total Submissions: 58492 Accepted: 20318 Description A palindrom