这题题目大意是给你一个数,问把这个数拆成若干个数相加,可以有多少种拆法.
开始没甚么思路,后来想到用dp做.
定义状态dp[i][j]为把数字i拆成j个数相加有多少种拆法.
其实有了思路就简单了:拆数字不如合并数字来得容易,把某个数n拆成x(1<=x<=n)份,等价于把n个1随意合并,合并成1到n份.然后看下面:
从例子出发,比如10这个数,我试着拆分,可以分成1~10份.
1.分5~10份时(也就是把n拆成>=n/2份),其实就相当于从10个1中拿出0~5个,然后把它们搞一搞,可以两两组合等等,反正不管怎么搞,既然是动态规划,我们根本不需要
在意此等细节,具体来说,分5份时,就是留5个1不动,把其它5个1搞成1到5份,其实就相当于求解把5分成若干个数相加,有多少种分法,这时我们看到了子问题的身影了,所以等价于dp[5][k] k=1,2,...5
分6份,时,就是留6个1不动,拿出剩下的4个1搞一搞,搞成1~4份然后丢向这6个1,由于都是1,所以它们之间是等价的.有dp[4][k],k=1,2,3,4种分法
分7份时,就是留7个1不动,拿出剩下的3个1搞成1~3份再砸那7个1,砸到谁就和谁结合了...dp[3][1]+dp[3][2]+dp[3][3]
如此一来,我们可以知道dp[10][j](5<=j<=10) = sum{dp[i-j][k]} (k=1,2,...i-j)
2.分1~4份时(也就是把n拆成<=n/2-1份,小于一半),就不能和上面那么搞了,因为这时比如我拿出6个1,搞一搞,不能搞成5份然后和剩下的4个1结合,因为只剩4个
不动的1了~~但是我们可以知道,这6个1可以分成1份,2份,3份,最多分4份,所以dp[10][4] = dp[6][k](k=1,2,3,4)
其它也是类似的,然后可以得出dp[10][j](1<=j<=4) = sum{dp[i-j][k]} (k=1,2,...j)
当然,上面两个式子可以合并:dp[10][j](1<=j<=10) = sum{dp[i-j][k]} (1<=k<=max{j, i-j})
3.经过上面的例子分析,得到最终的状态转移方程:dp[i][j] = sum{dp[i-j][k]}, 1<=k<=max{j, i-j}, 1<=j<=i.(j是份数,所以当然是属于[1,n]的)
4.但是故事还没有结束,这题最坑爹的地方在于它的整数可以达到600,从上面累加的夸张程度就可以看出来,这尼玛比斐波那契数列涨得还快!挂了两次,痛定思痛,我是
后来才发现这尼玛随便一个第200项就爆long long 了!!!所以找了一个大整数的模板,然后乖乖AC...大整数部分的模板可以不用在意,直接拿来用就好了,重点还是
后面的dp计算.另外我定义了dp[i][0]为把数字i分成若干份的结果也就是dp[i][0] = dp[i][1]+dp[i][2]+...+dp[i][i-1]+dp[i][i],这样在把n分成大于n/2份时,
要用到的sum{dp[i-j][k]}, k=1,2,...,i-j就可以直接取用dp[i-j][0]了,因为dp[i-j][0]就等于dp[i-j][1]+dp[i-j][2]+...+dp[i-j][i-j].#include <map>
#include <set>
#include <cmath>
#include <queue>
#include <stack>
#include <vector>
#include <bitset>
#include <string>
#include <cstring>
#include <climits>
#include <cstdio>
#include <iostream>
#include <algorithm>
using namespace std;class BigNum;
istream& operator>>(istream&,  BigNum&);
ostream& operator<<(ostream&,  BigNum&);#define MAXN 9999
#define MAXSIZE 40
#define DLEN 4class BigNum {
public:int a[MAXSIZE];int len;
public:BigNum(){len = 1;memset(a,0,sizeof(a));}BigNum(const int);BigNum(const char*);BigNum(const BigNum &);BigNum &operator=(const BigNum &);friend istream& operator>>(istream&,  BigNum&);friend ostream& operator<<(ostream&,  BigNum&);BigNum operator+(const BigNum &) const;BigNum operator-(const BigNum &) const;BigNum operator*(const BigNum &) const;BigNum operator/(const int  &) const;BigNum operator^(const int  &) const;int    operator%(const int  &) const;bool   operator>(const BigNum & T)const;bool   operator==(const BigNum & T)const;bool   operator==(const int & t)const;bool   operator>(const int & t)const;
};istream& operator>>(istream& in,  BigNum& b) {char ch[MAXSIZE*4];int i = -1;in >> ch;int l = strlen(ch);int cnt = 0, sum = 0;for (i=l-1;i>=0;) {sum = 0;int t = 1;for (int j = 0;j < 4 && i >= 0;j++, i--, t*=10){sum+=(ch[i]-'0')*t;}b.a[cnt]=sum;cnt++;}b.len = cnt++;return in;
}ostream& operator<<(ostream& out,  BigNum& b) {int i;cout << b.a[b.len - 1];for (i = b.len - 2 ; i >= 0 ; i--){cout.width(DLEN);cout.fill('0');cout << b.a[i];}return out;
}BigNum::BigNum(const int b)
{int c,d = b;len = 0;memset(a,0,sizeof(a));while (d > MAXN){c = d - (d / (MAXN + 1)) * (MAXN + 1);d = d / (MAXN + 1);  a[len++] = c;}a[len++] = d;
}BigNum::BigNum(const char*s)
{int t,k,index,l;memset(a,0,sizeof(a));l=strlen(s);len=l/DLEN;if (l%DLEN)len++;index=0;for (int i=l-1;i>=0;i-=DLEN){t=0;k=i-DLEN+1;if (k<0)k=0;for (int j=k;j<=i;j++)t=t*10+s[j]-'0';a[index++]=t;}
}BigNum::BigNum(const BigNum & T) : len(T.len)
{int i;memset(a,0,sizeof(a));for (i = 0 ; i < len ; i++)  a[i] = T.a[i];
}BigNum & BigNum::operator=(const BigNum & n)
{len = n.len;memset(a,0,sizeof(a));for (int i = 0 ; i < len ; i++)a[i] = n.a[i];return *this;
}BigNum BigNum::operator+(const BigNum & T) const
{BigNum t(*this);int i,big;big = T.len > len ? T.len : len;for (i = 0 ; i < big ; i++){t.a[i] +=T.a[i];if (t.a[i] > MAXN){t.a[i + 1]++;t.a[i] -=MAXN+1;}}if (t.a[big] != 0) t.len = big + 1;else t.len = big;return t;
}BigNum BigNum::operator-(const BigNum & T) const
{int i,j,big;bool flag;BigNum t1,t2;if (*this>T){t1=*this;t2=T;flag=0;}else{t1=T;t2=*this;flag=1;}big=t1.len;for (i = 0 ; i < big ; i++){if (t1.a[i] < t2.a[i]){j = i + 1;while (t1.a[j] == 0) j++;t1.a[j--]--;while (j > i) t1.a[j--] += MAXN;t1.a[i] += MAXN + 1 - t2.a[i];}else t1.a[i] -= t2.a[i];}t1.len = big;while (t1.a[len - 1] == 0 && t1.len > 1){t1.len--;big--;}if (flag)t1.a[big-1]=0-t1.a[big-1];return t1;
}
BigNum BigNum::operator*(const BigNum & T) const
{BigNum ret;int i,j,up;int temp,temp1;for (i = 0 ; i < len ; i++){up = 0;for (j = 0 ; j < T.len ; j++){temp = a[i] * T.a[j] + ret.a[i + j] + up;if (temp > MAXN){temp1 = temp - temp / (MAXN + 1) * (MAXN + 1);up = temp / (MAXN + 1);ret.a[i + j] = temp1;}else{up = 0;ret.a[i + j] = temp;}}if (up != 0)ret.a[i + j] = up;}ret.len = i + j;while (ret.a[ret.len - 1] == 0 && ret.len > 1) ret.len--;return ret;
}
BigNum BigNum::operator/(const int & b) const
{BigNum ret;int i,down = 0;for (i = len - 1 ; i >= 0 ; i--){ret.a[i] = (a[i] + down * (MAXN + 1)) / b;down = a[i] + down * (MAXN + 1) - ret.a[i] * b;}ret.len = len;while (ret.a[ret.len - 1] == 0 && ret.len > 1) ret.len--;return ret;
}
int BigNum::operator %(const int & b) const
{int i,d=0;for (i = len-1; i>=0; i--){d = ((d * (MAXN+1))% b + a[i])% b;}return d;
}
BigNum BigNum::operator^(const int & n) const
{BigNum t,ret(1);int i;if (n<0)exit(-1);if (n==0)return 1;if (n==1)return *this;int m=n;while (m>1){t=*this;for ( i=1;i<<1<=m;i<<=1){t=t*t;}m-=i;ret=ret*t;if (m==1)ret=ret*(*this);}return ret;
}
bool BigNum::operator>(const BigNum & T) const
{int ln;if (len > T.len) return true;else if (len == T.len){ln = len - 1;while (a[ln] == T.a[ln] && ln >= 0) ln--;if (ln >= 0 && a[ln] > T.a[ln]) return true;else return false;}else return false;
}bool BigNum::operator==(const BigNum & T) const
{int ln;if (len != T.len) return false;else{ln = len - 1;while (a[ln] == T.a[ln] && ln-- );if (ln < 0) return true;else return false;}
}bool BigNum::operator >(const int & t) const
{BigNum b(t);return *this>b;
}bool BigNum::operator==(const int & t) const
{BigNum b(t);return *this == b;
}/* 上面部分是模板辣 */
const int _DP = 601;
BigNum dp[_DP][_DP];
BigNum tmp(1);int main() {for (int i = 0; i < _DP; ++i) dp[0][i] = tmp; //初始化dp[0][i]为1,为什么呢?其实也可以不用,但是下面就要j<i了for (int i = 1; i < _DP; ++i) {for (int j = 0; j <= (i>>1); ++j) {for (int k = 1; k <= j; ++k)dp[i][j] = dp[i][j] + dp[i-j][k];dp[i][0] = dp[i][0] + dp[i][j];}for (int j = (i>>1)+1; j <= i; ++j) {//也就是这里,就要j<i了,并且还要令dp[i][i] = 1,然后这个1也要记得加到dp[i][0]中去dp[i][j] = dp[i-j][0];dp[i][0] = dp[i][0] + dp[i][j];}}int n;ios::sync_with_stdio(false);    //stream流加速,但是在toj上貌似效果不明显...while(cin >> n && n) {cout << dp[n][0] << endl;}return 0;
}

当然,本题可以用大进制数,比如千万进制数,可以很方便地处理,并且可以节省很多时间,用类模板,毕竟省事一些...但是很慢,跑了1.01s,如果直接来个亿进制,可以控制到0.02s以内.这里不赘述了.

toj1746How Many Sums相关推荐

  1. usaco ★Subset Sums 集合

    ★Subset Sums 集合 对于从 1 到 N 的连续整集合合,能划分成两个子集合,且保证每个集合的数字和是相等的. 举个例子,如果 N=3,对于{1,2,3}能划分成两个子集合,他们每个的所有数 ...

  2. 373. Find K Pairs with Smallest Sums (java,优先队列)

    题目: You are given two integer arrays nums1 and nums2 sorted in ascending order and an integer k. Def ...

  3. R计算数组的累计加和(Cumulative Sums)

    R计算数组的累计加和(Cumulative Sums) 目录 R计算数组的累计加和(Cumulative Sums) R中的累加和 可视化R中的累加和

  4. USACO 2.2.2 Subset Sums解题报告

    分类:DP,递推,记忆化搜索 作者:ACShiryu 时间:2011-7-15 Subset Sums JRM For many sets of consecutive integers from 1 ...

  5. [Swift]LeetCode373. 查找和最小的K对数字 | Find K Pairs with Smallest Sums

    ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★ ➤微信公众号:山青咏芝(shanqingyongzhi) ➤博客园地址:山青咏芝(https://www.cnblog ...

  6. spoj453 Sums in a Triangle (tutorial) 动态规划

    题意:给出一个三角矩形,求从顶部到最底部的最大值 思路:动态规划,用 dp(i,j)表示从(0,0)到(i,j)的最大值,有dp(i,j)= max(dp(i-1,j-1) , dp(i-1,j)+m ...

  7. 洛谷P1466 集合 Subset Sums

    P1466 集合 Subset Sums 162通过 308提交 题目提供者该用户不存在 标签USACO 难度普及/提高- 提交  讨论  题解 最新讨论 暂时没有讨论 题目描述 对于从1到N (1 ...

  8. 4kyu Sums of Perfect Squares

    4kyu Sums of Perfect Squares 题目背景: The task is simply stated. Given an integer n (3 < n < 109) ...

  9. 5kyu Square sums (simple)

    5kyu Square sums (simple) 题目背景: Task Write function square_sums_row (or squareSumsRow/SquareSumsRow ...

最新文章

  1. Java并发系列—工具类:CountDownLatch
  2. IE开发人员工具之实用功能讲解
  3. sierra mysql_macOS High Sierra 使用 Homebrew 安装 MYSQL 5.7
  4. 基于Echarts的HTML5 Canvas折线图柱状图DEMO演示
  5. 安卓 Input Events(输入事件)
  6. python下载安装搭建
  7. mc有什么红石机器人_我的世界10月考试!来测测你的MC成绩吧~
  8. python-数据容器-有序容器与无序容器
  9. (40)VHDL实现移位寄存器(方法2)
  10. [转]很经典的http协议详解
  11. 微软欲打造开发者联盟!
  12. Matlab程序中调用其他程序
  13. h264文件视频存储格式和音频存储格式
  14. FPGA 38译码器
  15. 个人独资有限公司章程模板
  16. h5页面制作软件html包,iH5专业H5页面制作工具网页版
  17. matlab工作区中的参数清除,【单选题】清空MATLAB工作区中所有变量的命令是_____。 (7.0分) A. clc B. c...
  18. matlab读取一幅灰度图,Matlab处理灰度图
  19. php Y2K38 漏洞解决方法
  20. 2019广州大学城第二届“论客杯”青年公益微创投暨南大学校际公开赛决赛圆满落幕

热门文章

  1. WordPress空间靠谱国内外一览
  2. 爱我专业主题黑板报计算机,我爱我班主题黑板报
  3. 彻底理解git 本地分支与远程分支,以及git pull与git fetch的区别, 以及git status输出的“Your branch is behind xxx”
  4. 网上花店html php,基于PHP+MYSQL的网上鲜花店销售系统(含论文)
  5. Java岗大厂面试百日冲刺 - 日积月累,每日三题【Day25】—— JVM1
  6. 声纹技术(五):声纹分割聚类技术
  7. 2020年下半年系统集成项目管理工程师上午真题及答案
  8. 杰理之MIDI 乐谱解码 【篇】
  9. sqlserver2012查看表大小情况
  10. bzoj3219 巡游