背包问题 2 完全背包解题报告

来源:互联网 发布:树状结构软件 编辑:程序博客网 时间:2024/05/17 08:17

Suppose there are 5 types of coins: 50-cent, 25-cent, 10-cent, 5-cent, and 1-cent. We want to make
changes with these coins for a given amount of money.
For example, if we have 11 cents, then we can make changes with one 10-cent coin and one 1-cent
coin, two 5-cent coins and one 1-cent coin, one 5-cent coin and six 1-cent coins, or eleven 1-cent coins.
So there are four ways of making changes for 11 cents with the above coins. Note that we count that
there is one way of making change for zero cent.
Write a program to find the total number of different ways of making changes for any amount of
money in cents. Your program should be able to handle up to 7489 cents.
Input
The input file contains any number of lines, each one consisting of a number for the amount of money
in cents.
Output
For each input line, output a line containing the number of different ways of making changes with the
above 5 types of coins.
Sample Input
11
26
Sample Output
4
13

题意:就是给你n美分,然后问你有几种方案数(已知有50美分,25美分,10美分,5美分,1,美分)

ac code:

#include <sstream>#include <iostream>#include <cstdio>#include <cstring>#include <string>#include <cstdlib>#include <cmath>#include <vector>#include <list>#include <deque>#include <queue>#include <iterator>#include <stack>#include <map>#include <set>#include <algorithm>#include <cctype>using namespace std;#define si1(a) scanf("%d",&a)#define si2(a,b) scanf("%d%d",&a,&b)#define sd1(a) scanf("%lf",&a)#define sd2(a,b) scanf("%lf%lf",&a,&b)#define ss1(s)  scanf("%s",s)#define pi1(a)    printf("%d\n",a)#define pi2(a,b)  printf("%d %d\n",a,b)#define mset(a,b)   memset(a,b,sizeof(a))#define forb(i,a,b)   for(int i=a;i<b;i++)#define ford(i,a,b)   for(int i=a;i<=b;i++)typedef long long LL;const int N=1e5+5;const int M=6666666;const int INF=0x3f3f3f3f;const double PI=acos(-1.0);const double eps=1e-7;const LL mod=1e9+7;int dp[8000];int n;int a[5];int main(){    a[0]=50,a[1]=25,a[2]=10,a[3]=5,a[4]=1;dp[0]=1;//初始化的时候0美分的方案数为1种    for(int i=0;i<5;i++)    {        for(int j=a[i];j<=8000;j++)        {            dp[j]+=dp[j-a[i]];//完全背包,进行更新方案数        }    }    while(~scanf("%d",&n))    {        printf("%d\n",dp[n]);//从打好的表里面找    }}


New Zealand currency consists of $100, $50, $20, $10, and $5 notes and $2, $1, 50c, 20c, 10c and 5c
coins. Write a program that will determine, for any given amount, in how many ways that amount
may be made up. Changing the order of listing does not increase the count. Thus 20c may be made
up in 4 ways: 1×20c, 2×10c, 10c+2×5c, and 4×5c.
Input
Input will consist of a series of real numbers no greater than $300.00 each on a separate line. Each
amount will be valid, that is will be a multiple of 5c. The file will be terminated by a line containing
zero (0.00).
Output
Output will consist of a line for each of the amounts in the input, each line consisting of the amount
of money (with two decimal places and right justified in a field of width 6), followed by the number of
ways in which that amount may be made up, right justified in a field of width 17.
Sample Input
0.20
2.00
0.00
Sample Output
0.20 4
2.00 293

题意同上

ac code:

#include <sstream>#include <iostream>#include <cstdio>#include <cstring>#include <string>#include <cstdlib>#include <cmath>#include <vector>#include <list>#include <deque>#include <queue>#include <iterator>#include <stack>#include <map>#include <set>#include <algorithm>#include <cctype>using namespace std;#define si1(a) scanf("%d",&a)#define si2(a,b) scanf("%d%d",&a,&b)#define sd1(a) scanf("%lf",&a)#define sd2(a,b) scanf("%lf%lf",&a,&b)#define ss1(s)  scanf("%s",s)#define pi1(a)    printf("%d\n",a)#define pi2(a,b)  printf("%d %d\n",a,b)#define mset(a,b)   memset(a,b,sizeof(a))#define forb(i,a,b)   for(int i=a;i<b;i++)#define ford(i,a,b)   for(int i=a;i<=b;i++)typedef long long LL;const int N=1e5+5;const int M=6666666;const int INF=0x3f3f3f3f;const double PI=acos(-1.0);const double eps=1e-7;const LL mod=1e9+7;LL dp[40000];int c,b;int a[11];int main(){    a[0]=10000,a[1]=5000,a[2]=2000,a[3]=1000,a[4]=500,a[5]=200,a[6]=100,a[7]=50,a[8]=20;//先将硬币的数额等比例扩大    a[9]=10,a[10]=5;    dp[0]=1;    for(int i=0;i<11;i++)    {        for(int j=a[i];j<=30010;j++)        {            dp[j]+=dp[j-a[i]];        }    }    while(~scanf("%d.%d",&c,&b)&&(c+b))    {        int n=100*c+b;        printf("%6.2lf%17lld\n",n*1.0/100,dp[n]);//注意输出格式    }}

Farmer John goes to Dollar Days at The Cow Store and discovers an unlimited number of tools on sale. During his first visit, the tools are selling variously for $1, $2, and $3. Farmer John has exactly $5 to spend. He can buy 5 tools at $1 each or 1 tool at $3 and an additional 1 tool at $2. Of course, there are other combinations for a total of 5 different ways FJ can spend all his money on tools. Here they are: 

        1 @ US$3 + 1 @ US$2        1 @ US$3 + 2 @ US$1        1 @ US$2 + 3 @ US$1        2 @ US$2 + 1 @ US$1        5 @ US$1
Write a program than will compute the number of ways FJ can spend N dollars (1 <= N <= 1000) at The Cow Store for tools on sale with a cost of $1..$K (1 <= K <= 100).
Input
A single line with two space-separated integers: N and K.
Output
A single line with a single integer that is the number of unique ways FJ can spend his money.
Sample Input
5 3
Sample Output
5


题意跟之前的差不多


ac code:

#include <sstream>#include <iostream>#include <cstdio>#include <cstring>#include <string>#include <cstdlib>#include <cmath>#include <vector>#include <list>#include <deque>#include <queue>#include <iterator>#include <stack>#include <map>#include <set>#include <algorithm>#include <cctype>using namespace std;#define si1(a) scanf("%d",&a)#define si2(a,b) scanf("%d%d",&a,&b)#define sd1(a) scanf("%lf",&a)#define sd2(a,b) scanf("%lf%lf",&a,&b)#define ss1(s)  scanf("%s",s)#define pi1(a)    printf("%d\n",a)#define pi2(a,b)  printf("%d %d\n",a,b)#define mset(a,b)   memset(a,b,sizeof(a))#define forb(i,a,b)   for(int i=a;i<b;i++)#define ford(i,a,b)   for(int i=a;i<=b;i++)typedef long long LL;const int N=1e5+5;const int M=6666666;const int INF=0x3f3f3f3f;const double PI=acos(-1.0);const double eps=1e-7;const LL mod=1e18;LL dp[1005][2];//dp[i][1] 代表i美分1e18以上的数位,dp[i][0]代表i美分1e18内的数位 int a[105];int main(){    int n,k;    for(int i=1;i<=101;i++) a[i]=i;    while(~scanf("%d%d",&n,&k))    {        mset(dp,0);        dp[0][0]=1;        for(int i=1;i<=k;i++)        {            for(int j=a[i];j<=n;j++)            {                dp[j][1]= dp[j][1]+dp[j-a[i]][1]+(dp[j][0]+dp[j-a[i]][0])/mod;//由于数据过于庞大,所以需要有到一点点特殊处理                dp[j][0]=(dp[j][0]+dp[j-a[i]][0])%mod;               // printf("%d %d\n",dp[j],a[i]);            }        }        if(dp[n][1])            printf("%lld",dp[n][1]);        printf("%lld\n",dp[n][0]);    }}


Charlie is a driver of Advanced Cargo Movement, Ltd. Charlie drives a lot and so he often buys coffee at coffee vending machines at motorests. Charlie hates change. That is basically the setup of your next task. 

Your program will be given numbers and types of coins Charlie has and the coffee price. The coffee vending machines accept coins of values 1, 5, 10, and 25 cents. The program should output which coins Charlie has to use paying the coffee so that he uses as many coins as possible. Because Charlie really does not want any change back he wants to pay the price exactly. 
Input
Each line of the input contains five integer numbers separated by a single space describing one situation to solve. The first integer on the line P, 1 <= P <= 10 000, is the coffee price in cents. Next four integers, C1, C2, C3, C4, 0 <= Ci <= 10 000, are the numbers of cents, nickels (5 cents), dimes (10 cents), and quarters (25 cents) in Charlie's valet. The last line of the input contains five zeros and no output should be generated for it.
Output
For each situation, your program should output one line containing the string "Throw in T1 cents, T2 nickels, T3 dimes, and T4 quarters.", where T1, T2, T3, T4 are the numbers of coins of appropriate values Charlie should use to pay the coffee while using as many coins as possible. In the case Charlie does not possess enough change to pay the price of the coffee exactly, your program should output "Charlie cannot buy coffee.".
Sample Input
12 5 3 1 216 0 0 0 10 0 0 0 0
Sample Output
Throw in 2 cents, 2 nickels, 0 dimes, and 0 quarters.Charlie cannot buy coffee.


题意很好懂。

题解:需要用到完全背包的记录路径,有点像回溯的感觉


ac code:

#include <iostream>#include <cstdio>#include <cstring>#include <string>#include <cstdlib>#include <cmath>#include <vector>#include <list>#include <deque>#include <queue>#include <iterator>#include <stack>#include <map>#include <set>#include <algorithm>#include <cctype>using namespace std;#define si1(a) scanf("%d",&a)#define si2(a,b) scanf("%d%d",&a,&b)#define sd1(a) scanf("%lf",&a)#define sd2(a,b) scanf("%lf%lf",&a,&b)#define ss1(s)  scanf("%s",s)#define pi1(a)    printf("%d\n",a)#define pi2(a,b)  printf("%d %d\n",a,b)#define mset(a,b)   memset(a,b,sizeof(a))#define forb(i,a,b)   for(int i=a;i<b;i++)#define ford(i,a,b)   for(int i=a;i<=b;i++)typedef long long LL;const int N=1100001;const int M=6666666;const int INF=0x3f3f3f3f;const double PI=acos(-1.0);const double eps=1e-7;int dp[10005];int path[10005];int usd[10005];//记录使用的硬币个数int main(){    int p,c1,c2,c3,c4;    int a[4]={1,5,10,25};    int num[4];    while(~scanf("%d%d%d%d%d",&p,&num[0],&num[1],&num[2],&num[3])&&(num[0]+num[1]+num[2]+num[3]+p))    {        mset(dp,-INF);        dp[0]=0;        path[0]=-1;//初始化路径        for(int i=0;i<4;i++)        {            mset(usd,0);            for(int j=a[i];j<=p;j++)            {                if(dp[j-a[i]]+1>dp[j]&&dp[j-a[i]]>=0&&usd[j-a[i]]<num[i])                {                    dp[j]=dp[j-a[i]]+1;//使用总的硬币个数加一                    usd[j]=usd[j-a[i]]+1;//使用该类硬币个数加一                    path[j]=j-a[i];//记录路径                }            }        }        if(dp[p]<0)        {            printf("Charlie cannot buy coffee.\n");        }        else        {            int ans[105];            mset(ans,0);            while(path[p]!=-1)            {                ans[p-path[p]]++;//path[j]=j-a[i]; 将a[i]和path[j]换个位置就知道了,很巧妙的回溯回去                p=path[p];            }            printf("Throw in %d cents, %d nickels, %d dimes, and %d quarters.\n",ans[a[0]],ans[a[1]],ans[a[2]],ans[a[3]]);        }    }    return 0;}

Farmer John has gone to town to buy some farm supplies. Being a very efficient man, he always pays for his goods in such a way that the smallest number of coins changes hands, i.e., the number of coins he uses to pay plus the number of coins he receives in change is minimized. Help him to determine what this minimum number is.

FJ wants to buy T (1 ≤ T ≤ 10,000) cents of supplies. The currency system has N (1 ≤ N ≤ 100) different coins, with values V1V2, ..., VN (1 ≤ Vi ≤ 120). Farmer John is carrying C1 coins of value V1C2 coins of value V2, ...., and CN coins of value VN (0 ≤ Ci ≤ 10,000). The shopkeeper has an unlimited supply of all the coins, and always makes change in the most efficient manner (although Farmer John must be sure to pay in a way that makes it possible to make the correct change).

Input
Line 1: Two space-separated integers: N and T
Line 2: N space-separated integers, respectively V 1V 2, ..., VN coins ( V 1, ...VN
Line 3: N space-separated integers, respectively C 1C 2, ..., CN
Output
Line 1: A line containing a single integer, the minimum number of coins involved in a payment and change-making. If it is impossible for Farmer John to pay and receive exact change, output -1.
Sample Input
3 705 25 505 2 1
Sample Output
3
Hint
Farmer John pays 75 cents using a 50 cents and a 25 cents coin, and receives a 5 cents coin in change, for a total of 3 coins used in the transaction.

题意:需要求出最小的使用的硬币个数

题解:需要用到多重背包以及完全背包求解(还是没写出来,最后看了大佬的题解才过的……)


ac code:

#include <iostream>#include <cstdio>#include <cstring>#include <string>#include <cstdlib>#include <cmath>#include <vector>#include <list>#include <deque>#include <queue>#include <iterator>#include <stack>#include <map>#include <set>#include <algorithm>#include <cctype>using namespace std;#define si1(a) scanf("%d",&a)#define si2(a,b) scanf("%d%d",&a,&b)#define sd1(a) scanf("%lf",&a)#define sd2(a,b) scanf("%lf%lf",&a,&b)#define ss1(s)  scanf("%s",s)#define pi1(a)    printf("%d\n",a)#define pi2(a,b)  printf("%d %d\n",a,b)#define mset(a,b)   memset(a,b,sizeof(a))#define forb(i,a,b)   for(int i=a;i<b;i++)#define ford(i,a,b)   for(int i=a;i<=b;i++)typedef long long LL;const int N=1100001;const int M=6666666;const int INF=0x3f3f3f3f;const double PI=acos(-1.0);const double eps=1e-7;int dp1[25005];int dp2[25005];struct coins{    int num,val;}a[125];int main(){    int n,p;    while(~scanf("%d%d",&n,&p))    {        int mmax=0;        for(int i=0;i<n;i++)        {            scanf("%d",&a[i].val);            mmax=max(mmax,a[i].val);//记录硬币的最大值        }        for(int i=0;i<n;i++)            scanf("%d",&a[i].num);        mmax=mmax*mmax;        int P=p+mmax;//记录最大的背包容量,好像用到鸽巢定理(好像是这个吧……)        mset(dp1,INF);        mset(dp2,INF);        dp1[0]=dp2[0]=0;        for(int i=0;i<n;i++)        {            for(int j=a[i].val;j<mmax;j++)            {                dp1[j]=min(dp1[j],dp1[j-a[i].val]+1);//记录老板找j元的钱的最小硬币数            }        }        for(int i=0;i<n;i++)        {            int k=1;            int sum=0;            while(sum<a[i].num)            {                for(int j=P;j>=a[i].val*k;j--)//这里需要用多重背包,记录给j元的最小硬币数                {                    dp2[j]=min(dp2[j],dp2[j-a[i].val*k]+k);                }                sum+=k;//二进制优化的感觉                if(sum+2*k>a[i].num)                    k=a[i].num-sum;                else k*=2;            }        }        int mmin=INF;        for(int i=p;i<=P;i++)        {            mmin=min(mmin,dp2[i]+dp1[i-p]);//进行维护一个最小数        }        if(mmin==INF)            printf("-1\n");        else            printf("%d\n",mmin);    }    return 0;}

John never knew he had a grand-uncle, until he received the notary's letter. He learned that his late grand-uncle had gathered a lot of money, somewhere in South-America, and that John was the only inheritor. 
John did not need that much money for the moment. But he realized that it would be a good idea to store this capital in a safe place, and have it grow until he decided to retire. The bank convinced him that a certain kind of bond was interesting for him. 
This kind of bond has a fixed value, and gives a fixed amount of yearly interest, payed to the owner at the end of each year. The bond has no fixed term. Bonds are available in different sizes. The larger ones usually give a better interest. Soon John realized that the optimal set of bonds to buy was not trivial to figure out. Moreover, after a few years his capital would have grown, and the schedule had to be re-evaluated. 
Assume the following bonds are available: 
ValueAnnual
interest4000
3000400
250

With a capital of e10 000 one could buy two bonds of $4 000, giving a yearly interest of $800. Buying two bonds of $3 000, and one of $4 000 is a better idea, as it gives a yearly interest of $900. After two years the capital has grown to $11 800, and it makes sense to sell a $3 000 one and buy a $4 000 one, so the annual interest grows to $1 050. This is where this story grows unlikely: the bank does not charge for buying and selling bonds. Next year the total sum is $12 850, which allows for three times $4 000, giving a yearly interest of $1 200. 
Here is your problem: given an amount to begin with, a number of years, and a set of bonds with their values and interests, find out how big the amount may grow in the given period, using the best schedule for buying and selling bonds.
Input
The first line contains a single positive integer N which is the number of test cases. The test cases follow. 
The first line of a test case contains two positive integers: the amount to start with (at most $1 000 000), and the number of years the capital may grow (at most 40).
The following line contains a single number: the number d (1 <= d <= 10) of available bonds. 
The next d lines each contain the description of a bond. The description of a bond consists of two positive integers: the value of the bond, and the yearly interest for that bond. The value of a bond is always a multiple of $1 000. The interest of a bond is never more than 10% of its value.
Output
For each test case, output – on a separate line – the capital at the end of the period, after an optimal schedule of buying and selling.
Sample Input
110000 424000 4003000 250
Sample Output
14050

题意:就是进行投资……而且每年的本金会变,加上上一年的利润

题解:题目有说到所有的金额都是1000的倍数所有可以进行缩小,暴力模拟就好了


ac code:

#include <iostream>#include <cstdio>#include <cstring>#include <string>#include <cstdlib>#include <cmath>#include <vector>#include <list>#include <deque>#include <queue>#include <iterator>#include <stack>#include <map>#include <set>#include <algorithm>#include <cctype>using namespace std;#define si1(a) scanf("%d",&a)#define si2(a,b) scanf("%d%d",&a,&b)#define sd1(a) scanf("%lf",&a)#define sd2(a,b) scanf("%lf%lf",&a,&b)#define ss1(s)  scanf("%s",s)#define pi1(a)    printf("%d\n",a)#define pi2(a,b)  printf("%d %d\n",a,b)#define mset(a,b)   memset(a,b,sizeof(a))#define forb(i,a,b)   for(int i=a;i<b;i++)#define ford(i,a,b)   for(int i=a;i<=b;i++)typedef long long LL;const int N=1100001;const int M=6666666;const int INF=0x3f3f3f3f;const double PI=acos(-1.0);const double eps=1e-7;int c[55],v[55];int dp[100000];int main(){    int T;    si1(T);    while(T--)    {        int n,m;        si2(n,m);        int k;        si1(k);        for(int i=0;i<k;i++)        {            scanf("%d%d",&c[i],&v[i]);            c[i]/=1000;//进行缩小        }        for(int x=1;x<=m;x++)        {            int val=n/1000;//本金也要缩小相应的倍数            for(int i=0;i<k;i++)            {                for(int j=c[i];j<=val;j++)                {                    dp[j]=max(dp[j],dp[j-c[i]]+v[i]);//简单的完全背包                }            }            n+=dp[val];//更新背包            mset(dp,0);        }        printf("%d\n",n);    }    return 0;}

Battle Ships is a new game which is similar to Star Craft. In this game, the enemy builds a defense tower, which has L longevity. The player has a military factory, which can produce N kinds of battle ships. The factory takes ti seconds to produce the i-th battle ship and this battle ship can make the tower loss li longevity every second when it has been produced. If the longevity of the tower lower than or equal to 0, the player wins. Notice that at each time, the factory can choose only one kind of battle ships to produce or do nothing. And producing more than one battle ships of the same kind is acceptable.

Your job is to find out the minimum time the player should spend to win the game.

Input

There are multiple test cases. 
The first line of each case contains two integers N(1 ≤ N ≤ 30) and L(1 ≤ L ≤ 330), N is the number of the kinds of Battle Ships, L is the longevity of the Defense Tower. Then the following N lines, each line contains two integers i(1 ≤ i ≤ 20) and li(1 ≤ li ≤ 330) indicating the produce time and the lethality of the i-th kind Battle Ships.

<h4< dd="">
Output

Output one line for each test case. An integer indicating the minimum time the player should spend to win the game.

<h4< dd="">
Sample Input
1 11 12 101 12 53 1001 103 2010 100
<h4< dd="">
Sample Output
245


题意:建武器攻塔,暴力模拟

ac code:

#include <iostream>#include <cstdio>#include <cstring>#include <string>#include <cstdlib>#include <cmath>#include <vector>#include <list>#include <deque>#include <queue>#include <iterator>#include <stack>#include <map>#include <set>#include <algorithm>#include <cctype>using namespace std;#define si1(a) scanf("%d",&a)#define si2(a,b) scanf("%d%d",&a,&b)#define sd1(a) scanf("%lf",&a)#define sd2(a,b) scanf("%lf%lf",&a,&b)#define ss1(s)  scanf("%s",s)#define pi1(a)    printf("%d\n",a)#define pi2(a,b)  printf("%d %d\n",a,b)#define mset(a,b)   memset(a,b,sizeof(a))#define forb(i,a,b)   for(int i=a;i<b;i++)#define ford(i,a,b)   for(int i=a;i<=b;i++)typedef long long LL;const int N=1e5+5;const int M=6666666;const int INF=0x3f3f3f3f;const double PI=acos(-1.0);const double eps=1e-7;int a[350];int c[350];int v[350];int dp[350];int main(){    int n,l;    while(~scanf("%d%d",&n,&l))    {        mset(dp,0);        for(int i=0;i<n;i++)        {            scanf("%d%d",&c[i],&v[i]);        }        for(int i=0;i<n;i++)        {            for(int j=c[i]+1;;j++)            {                dp[j]=max(dp[j],dp[j-c[i]]+(j-c[i])*v[i]);//第j秒最多能打多少血                if(dp[j]>=l)                    break;            }        }        for(int i=1;;i++)        {            if(dp[i]>=l)//爆搜一遍            {                printf("%d\n",i);                break;            }        }    }    return 0;}

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

In class, I raised a new idea: "how to calculate the LCM of K numbers". It's also an easy problem indeed, which only cost me 1 minute to solve it. I raised my hand and told teacher about my outstanding algorithm. Teacher just smiled and smiled...

After class, my teacher gave me a new problem and he wanted me solve it in 1 minute, too. If we know three parameters N, M, K, and two equations:

1. SUM (A1, A2, ..., Ai, Ai+1,..., AK) = N 
2. LCM (A1, A2, ..., Ai, Ai+1,..., AK) = M

Can you calculate how many kinds of solutions are there for Ai (Ai are all positive numbers). I began to roll cold sweat but teacher just smiled and smiled.

Can you solve this problem in 1 minute?

Input

There are multiple test cases.

Each test case contains three integers N, M, K. (1 ≤ N, M ≤ 1,000, 1 ≤ K ≤ 100)

<h4< dd="">
Output

For each test case, output an integer indicating the number of solution modulo 1,000,000,007(1e9 + 7).

You can get more details in the sample and hint below.

<h4< dd="">
Sample Input
4 2 23 2 2
<h4< dd="">
Sample Output
12
<h4< dd="">
Hint

The first test case: the only solution is (2, 2).

The second test case: the solution are (1, 2) and (2, 1).


题解:把每个m的因子当作物品,要求我们随便选k个物品,使得这些物品的总和为n,Lcm为m。dp[i][j][k]表示选了i个物品,和为jlcm为k的方案数,具体做法是先预处理找出m的所有因子,这样不管怎么选,最后都有可能Lcm为m,免除很多无必要的计算,然后用这类背包的方法进行转移。(网上大佬的想法,我还是没写出来……)

ac code:

#include <iostream>#include <cstdio>#include <cstring>#include <string>#include <cstdlib>#include <cmath>#include <vector>#include <list>#include <deque>#include <queue>#include <iterator>#include <stack>#include <map>#include <set>#include <algorithm>#include <cctype>using namespace std;#define si1(a) scanf("%d",&a)#define si2(a,b) scanf("%d%d",&a,&b)#define sd1(a) scanf("%lf",&a)#define sd2(a,b) scanf("%lf%lf",&a,&b)#define ss1(s)  scanf("%s",s)#define pi1(a)    printf("%d\n",a)#define pi2(a,b)  printf("%d %d\n",a,b)#define mset(a,b)   memset(a,b,sizeof(a))#define forb(i,a,b)   for(int i=a;i<b;i++)#define ford(i,a,b)   for(int i=a;i<=b;i++)typedef long long LL;const int N=1e5;const int M=6666666;const int INF=0x3f3f3f3f;const double PI=acos(-1.0);const double eps=1e-7;const int mod = 1e9+7;int dp[2][1005][105];//用到了滚动数组,真是神奇的东西int a[1005],len,pos[1005];int n,m,k;int hash[1005][1005];int gcd(int a,int b){    return b==0?a:gcd(b,a%b);}int lcm(int a,int b){    return a/gcd(a,b)*b;}int main(){    for(int i=1;i<=1000;i++)    {        for(int j=1;j<=1000;j++)        {            hash[i][j]=lcm(i,j);//记录最小公倍数        }    }    while(~scanf("%d%d%d",&n,&m,&k))    {        len = 0;        mset(pos,-1);        for(int i = 1;i <=m; i++)        {            if(m%i==0)            {                a[len] = i;                pos[i] = len++;//将m的因子进行离散化            }        }        mset(dp[0],-1);        dp[0][0][0] = 1;        for(int i = 1; i <=k ; i++)        {            mset(dp[i%2],-1);//清空上一轮的数据            for(int j = i-1; j<=n;j++)//第i个数,那么前i-1个数的和最小就是i-1(都是1的情况)            {                for(int x = 0;x<len;x++)                {                    if(dp[(i+1)%2][j][x]==-1) continue;                    for(int y = 0;y<len&&(a[y]+j<=n);y++)                    {                        int r = hash[a[y]][a[x]];                        int s = a[y]+j;                        if(pos[r]!=-1&&r<=m)                        {                            r = pos[r];                            if(dp[i%2][s][r]==-1)dp[i%2][s][r]=0;                            dp[i%2][s][r]+=dp[(i+1)%2][j][x];//更新下一轮的数据                            dp[i%2][s][r]%=mod;                        }                    }                }            }        }        if(dp[k%2][n][pos[m]]==-1)            printf("0\n");        else            printf("%d\n",dp[k%2][n][pos[m]]);    }    return 0;}

未完待续……