微积分习题
小王是大一的学生,想在寒假里强化一下微积分课程的学习,他从图书馆借了一套吉米多维奇的数学分析习题集。他决定在以后的 n 天里要做完上面的 S 道积分题。
为了能够尽快地完成任务,小王强迫自己第 i 天至少要做 ai 道积分题。但是,小王在假期里还有其他事情(例如过春节),每天的题量不能太多,他估计了一下,第 i 天做的积分题不能超过 bi bi ai )道。
现在小王想知道,究竟能有多少种方案能够在 n 天里做完这 S 道习题呢?小王请你写个程序帮他算一算。
具体来说,一个方案就是每天做的微积分题的数目的序列,假设第 i 天完成 xi 道题( xi 当然满足 ai xi bi ,且 x 1 +x2+……+xn=S )。那么向量 (x1, x2, …, xn) 就对应了一个方案。两个方案不同是指它们对应的向量不同。
【输入】
一共 n +1 行,第一行是两个整数 n S ,用空格分开,分别表示天数和题目数( 1 ≤ n ≤ 20 1 ≤ S ≤ 1000 );接下来 n 行每行两个整数,之间用空格隔开,分别表示第 i 天对做题数量的限制 ai bi 0 ≤ ai bi S )。
【输出】
一个整数,表示满足条件的方案数 T
【输入输出】
 
样例 A
样例 B
样例 C
样例 D
输入样例
3 11
2 5
1 6
3 4
8 20
1 4
2 8
1 5
2 7
4 7
2 5
2 8
1 3
10 55
0 1
0 2
0 3
0 4
0 5
0 8
0 8
0 8
0 9
0 10
15 123
1 100
2 100
3 100
4 100
5 100
6 100
7 100
8 100
9 100
10 100
11 100
12 100
13 100
14 100
15 100
输出样例
8
731
209
680
 
#include <iostream>
#include <iomanip>
#include <vector>
#include <algorithm>
#include <functional>
using namespace std;
class BigNum
{
 vector<int> val;
public:
 static const int NUM = 10000;
 static const int WIDTH = 4;
 BigNum(int n = 0);
 friend ostream& operator << (ostream &out, const BigNum &n);
 bool operator != (const BigNum &n) const {return val != n.val;}
 BigNum& operator += (const BigNum &n2);
};
BigNum::BigNum(int n /* = 0 */)
{
 do // 保证val至少有一个元素
 {
  int a = n / NUM;
  int b = n % NUM;
  val.push_back(b);
  n = a;
 } while(n > 0);
}
BigNum& BigNum::operator += (const BigNum &n2)
{
 if (val.size() < n2.val.size()) // n2短
  val.resize(n2.val.size());
 transform(n2.val.begin(), n2.val.end(), val.begin(), val.begin(), plus<int>());
 int lastAdd = 0;
 for (vector<int>::iterator it = val.begin(); it != val.end(); ++it)
 {
  *it += lastAdd;
  if (*it >= BigNum::NUM)
  {
   *it -= BigNum::NUM;
   lastAdd = 1;
  }
  else
   lastAdd = 0;
 }
 if (lastAdd == 1)
  val.push_back(1);
 return *this;
}
ostream& operator << (ostream &out, const BigNum &n)
{
 if (n.val.size() == 1)  // 只有一个数
  return out << n.val[0];
 out << n.val.back();
 char c = out.fill('0');
 for (vector<int>::const_reverse_iterator it = n.val.rbegin()+1;
  it != n.val.rend(); ++it)
  out << setw(BigNum::WIDTH) << *it;
 return out << setfill(c);
}
#if 1 // 记录表法
const int MAX_N = 20;
const int MAX_S = 1000;
int n, S;
int a[MAX_N], b[MAX_N];
BigNum T[MAX_N][MAX_S + 1] = {{0}}; // 记录表
BigNum Cal(int day, int done, int min, int max)
{
 int left = S - done;   // 还有多少题要做
 if (left < min || left > max) // 超出可能的做题范围
  return 0;     // 方案必不成功,部分方案数为0
 if (day == n - 1)    // 最后一天,方案必然可能
  return 1;     // 部分方案数为1,递归终止
 if (T[day][done] != 0)   // 已经计算过
  return T[day][done];
 BigNum total = 0;    // 部分方案数
 for (int t = a[day]; t <= b[day]; t++)   // 枚举
  total += Cal(day + 1, done + t, min-a[day], max-b[day]); // 递归计算
 T[day][done] = total;   // 记录下来
 return total;
}
int main()
{
 // 读入数据
 cin >> n >> S;
 for (int i = 0; i < n; i++)
  cin >> a[i] >> b[i];
 int min = 0, max = 0;  // 最少和最多做题数量
 for (int i = 0; i < n; i++)
 {
  min += a[i];
  max += b[i];
 }
 cout << Cal(0, 0, min, max) << endl;
 return 0;
}
#else // 动态规划算法
const int MAX_N = 20;
const int MAX_S = 1000;
int n, S;
int a[MAX_N], b[MAX_N];
BigNum fa[MAX_N][MAX_S+1];
int main()
{
 // 读入数据
 cin >> n >> S;
 for (int i = 0; i < n; i++)
  cin >> a[i] >> b[i];
 int leftMin = 0, leftMax = 0; // 还剩下的天中最少和最多做题数
 for (int i = 0; i < n; i++)
 {
  leftMin += a[i];
  leftMax += b[i];
 }
 // 第0天
 int realMin = a[0], realMax = b[0]; // 到当前天为止,最少和最多做题数
 leftMin -= a[0]; leftMax -= b[0];
 if (realMin < S - leftMax) realMin = S - leftMax;
 if (realMax > S - leftMin) realMax = S - leftMin;
 for (int t = realMin; t <= realMax; t++)
  fa[0][t] = 1;
 for (int day = 1; day < n; day++)
 {
  realMin += a[day]; realMax += b[day];
  leftMin -= a[day]; leftMax -= b[day];
  if (realMin < S - leftMax) realMin = S - leftMax;
  if (realMax > S - leftMin) realMax = S - leftMin;
  for (int tall = realMin; tall <= realMax; tall++) // 对于总题量
   for (int t = a[day]; t <= b[day] && t <= tall; t++)
    fa[day][tall] += fa[day-1][tall-t]; // 累计之前的可能方案数
 }
 cout << fa[n-1][S] << endl;
 return 0;
}
#endif
 
Logo

20年前,《新程序员》创刊时,我们的心愿是全面关注程序员成长,中国将拥有新一代世界级的程序员。20年后的今天,我们有了新的使命:助力中国IT技术人成长,成就一亿技术人!

更多推荐