博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
算法擂台微积分习题问题解答
阅读量:139 次
发布时间:2019-02-27

本文共 3887 字,大约阅读时间需要 12 分钟。

 
微积分习题
小王是大一的学生,想在寒假里强化一下微积分课程的学习,他从图书馆借了一套吉米多维奇的数学分析习题集。他决定在以后的
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
 

转载地址:http://vdgf.baihongyu.com/

你可能感兴趣的文章