您的位置:首页 > 其它

hdu 1028 Ignatius and the Princess III(打表,后期进阶补->找规律和dp)

2018-01-16 20:39 507 查看
Problem Description

"Well, it seems the first problem is too easy. I will let you know how foolish you are later." feng5166 says.

"The second problem is, given an positive integer N, we define an equation like this:

  N=a[1]+a[2]+a[3]+...+a[m];

  a[i]>0,1<=m<=N;

My question is how many different equations you can find for a given N.

For example, assume N is 4, we can find:

  4 = 4;

  4 = 3 + 1;

  4 = 2 + 2;

  4 = 2 + 1 + 1;

  4 = 1 + 1 + 1 + 1;

so the result is 5 when N is 4. Note that "4 = 3 + 1" and "4 = 1 + 3" is the same in this problem. Now, you do it!" 

Input

The input contains several test cases. Each test case contains a positive integer N(1<=N<=120) which is mentioned above. The input is terminated by the end of file.

Output

For each test case, you have to output a line contains an integer P which indicate the different equations you have found.

Sample Input

4
10
20

Sample Output

5
42
627

好吧,这是基础题中的压轴,现在看回来思路都感觉挺复杂难受。

  4 = 4;
  4 = 3 + 1;
  4 = 2 + 2;
  4 = 2 + 1 + 1;
  4 = 1 + 1 + 1 + 1

看看规律先,他要求的数据范围是120,还好比较下,就算找不到规律,只要知道每个数怎么求的

直接可以暴力模拟保存,然后打表得出答案。

组成一个数字有多少种方案,其实换个角度,有多少个方案组成少于所给数

因为你组成任何数,都可以用1补齐。

我们可以说每走一步,后面的数字都可以加一。

道理很难讲,模拟一下就懂意思了:

假如求前10的答案:一开始重置为0,则:

第一遍模拟:数字:     1 2 3 4 5 6 7 8 9 10

                     答案:     0 0 0 0 0 0 0 0 0 0

从1开始,又1组成的式子,1+1+1+1+.....(避免答案重复所以后一个数字不大于前一个数字,这样就不会重复)

                     数字:     1 2 3 4 5 6 7 8 9 10

                     答案:     1 1 1 1 1 1 1 1 1  1

到2开始的式子:  2+ 1+1+1+1(后面n个1,所以2之后的数字都多了一种方案)

                      

                      数字:     1 2 3 4 5 6 7 8 9 10

                     答案:      1 2 2 2 2 2 2 2 2  2 

                           2 + 2+1+1+1(后面n个1,所以4之后的数字都多了一种方案)

                      

                      数字:     1 2 3 4 5 6 7 8 9 10

                     答案:      1 2 2 3 3 3 3 3 3  3  

(可以联想到,前面2个数字的方案已经定下来了,因为以后的起点都比他们大,他们方案数不会加了)

                      不断循环,2,4,6,8,10一直循环下去,每一个的后面数字都多了一种方案

   记住前提:每个个式子后一个数字都比前一个小。

  题目整理: 下面换一种走格子的思想,我要到达一个数字n,我第一步 a1<=n;

         后面的每一步都不能比第一步大,问有多少种方案到n。 

 所以我每走一步后面都可以加无限个1,那前缀后面的所有数字都可以多一个方案,因为以后不会再出现这个前缀

   比如我决定:2+2下一步走1,根据前提,我后面只能1了。2+2+1+1+1。。。

 简单来讲,每一个不同的前缀,后面的数字都加一,体会下:

for(i=maxvalue;i>=2;i--)  //maxvalue表示我可以走得最大步数(比前一步小)
{
if(weizhi+i>121) //避免没必要的循环,只求前120
continue;
ans[weizhi+i]++; //走到的位置+1
jisuan(i,weizhi+i);//走到某位置,进行抉择,则再运行一遍函数,注意带入的是i,因为走到这个位置最大就是i,不能带入maxvalue,因为这里的maxvalue是上一步的最大步数
}
for(i=weizhi+1;i<=121;i++) //后面的每一步都+1
ans[i]++;
  本来一开始写的是倒序,理解上容易一点,但是写起来发现正序好写,但是理解可能很困难。
  模拟一下就好了。

   以下是打表代码,用了80秒,因为暴力,没有优化。

#include <iostream>
#include <queue>
#include <string.h>
#include <string>
#include <algorithm>
#include <map>
#include <cstdio>
using namespace std;
int ans[150];
int min(int a,int b)
{
if(a<b)
return a;
return b;
}
void jisuan(int maxvalue,int weizhi) //value最大递减
{
int i,j;
for(i=maxvalue;i>=2;i--)
{
if(weizhi+i>121)
continue;
ans[weizhi+i]++;
jisuan(i,weizhi+i);
}
for(i=weizhi+1;i<=121;i++)
ans[i]++;
}
int main()
{
memset(ans,0,sizeof(ans));
int w;
for(w=1;w<=121;w++)
{
ans[w]++;
cout<<"1";
jisuan(min(w,121-w),w);
}
cout<<"2";
for(w=1;w<=121;w++)
cout<<ans[w]<<" ";

return 0;
} 输出结果:
1 2 3 5 7 11 15 22 30 42 56 77 101 135 176 231 297 385 490 627 792 1002 1255 1575 1958 2436 3010 3718 4565 5604 6842 8349 10143 12310 14883 17977 21637 26015 31185 37338 44583 53174 63261 75175 89134 105558 124754 147273 173525 204226 239943 281589 329931 386155 451276 526823 614154 715220 831820 966467 1121505 1300156 1505499 1741630 2012558 2323520 2679689 3087735 3554345 4087968 4697205 5392783 6185
4000
689 7089500 8118264 9289091 10619863 12132164 13848650 15796476 18004327 20506255 23338469 26543660 30167357 34262962 38887673 44108109 49995925 56634173 64112359 72533807 82010177 92669720 104651419 118114304 133230930 150198136 169229875 190569292 214481126 241265379 271248950 304801365 342325709 384276336 431149389 483502844 541946240 607163746 679903203 761002156 851376628 952050665 1064144451 1188908248 1327710076 1482074143 1653668665 1844349560 2056148051
Process returned 0 (0x0) execution time : 80.434 s
Press any key to continue. 把这些答案复制下来保存,根据输入的n输出数组答案就好了,就是把那80秒的运算放在电脑中
  如果范围太大就要找式子找规律,dp等其他方法。

  附上AC代码:

 #include <iostream>
#include <queue>
#include <string.h>
#include <string>
#include <algorithm>
#include <map>
#include <strstream>
#include <cstdio>
using namespace std;

int main()
{
long long int in[125];
char a[1000]="1 2 3 5 7 11 15 22 30 42 56 77 101 135 176 231 297 385 490 627 792 1002 1255 1575 1958 2436 3010 3718 4565 5604 6842 8349 10143 12310 14883 17977 21637 26015 31185 37338 44583 53174 63261 75175 89134 105558 124754 147273 173525 204226 239943 281589 329931 386155 451276 526823 614154 715220 831820 966467 1121505 1300156 1505499 1741630 2012558 2323520 2679689 3087735 3554345 4087968 4697205 5392783 6185689 7089500 8118264 9289091 10619863 12132164 13848650 15796476 18004327 20506255 23338469 26543660 30167357 34262962 38887673 44108109 49995925 56634173 64112359 72533807 82010177 92669720 104651419 118114304 133230930 150198136 169229875 190569292 214481126 241265379 271248950 304801365 342325709 384276336 431149389 483502844 541946240 607163746 679903203 761002156 851376628 952050665 1064144451 1188908248 1327710076 1482074143 1653668665 1844349560 2056148051";
istrstream strin(a, sizeof(a));
int i=0;
while(strin>>in[i])
{
i++;
}
int j;
while(cin>>j)
cout<<in[j-1]<<endl;
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  整式分解 打表