# 疯狂的采药
## 题目背景
此题为纪念 LiYuxiang 而生。
## 题目描述
LiYuxiang 是个天资聪颖的孩子,他的梦想是成为世界上最伟大的医师。为此,他想拜附近最有威望的医师为师。医师为了判断他的资质,给他出了一个难题。医师把他带到一个到处都是草药的山洞里对他说:“孩子,这个山洞里有一些不同种类的草药,采每一种都需要一些时间,每一种也有它自身的价值。我会给你一段时间,在这段时间里,你可以采到一些草药。如果你是一个聪明的孩子,你应该可以让采到的草药的总价值最大。”
如果你是 LiYuxiang,你能完成这个任务吗?
此题和原题的不同点:
$1$. 每种草药可以无限制地疯狂采摘。
$2$. 药的种类眼花缭乱,采药时间好长好长啊!师傅等得菊花都谢了!
## 输入格式
输入第一行有两个整数,分别代表总共能够用来采药的时间 $t$ 和代表山洞里的草药的数目 $m$。
第 $2$ 到第 $(m + 1)$ 行,每行两个整数,第 $(i + 1)$ 行的整数 $a_i, b_i$ 分别表示采摘第 $i$ 种草药的时间和该草药的价值。
## 输出格式
输出一行,这一行只包含一个整数,表示在规定的时间内,可以采到的草药的最大总价值。
## 样例 #1
### 样例输入 #1
```
70 3
71 100
69 1
1 2
```
### 样例输出 #1
```
140
```
## 提示
#### 数据规模与约定
- 对于 $30\%$ 的数据,保证 $m \le 10^3$ 。
- 对于 $100\%$ 的数据,保证 $1 \leq m \le 10^4$,$1 \leq t \leq 10^7$,且 $1 \leq m \times t \leq 10^7$,$1 \leq a_i, b_i \leq 10^4$。
就是01背包
#include
long long dp[10000001];
int time[10000001],money[10000001];
long long max(long long a,long long b)
{
if(a>b) return a;
else return b;
}
int main()
{
int i,j;
int t,m;
scanf("%d%d",&t,&m);
for(i=1;i<=m;i++)
{
scanf("%lld%lld",&time[i],&money[i]);
}
for(i=1;i<=m;i++)
{
for(j=time[i];j<=t;j++)
{
dp[j]=max(dp[j],dp[j-time[i]]+money[i]);
}
}
printf("%lld",dp[t]);
}
# [USACO1.5][IOI1994]数字三角形 Number Triangles
## 题目描述
观察下面的数字金字塔。
写一个程序来查找从最高点到底部任意处结束的路径,使路径经过数字的和最大。每一步可以走到左下方的点也可以到达右下方的点。
```cpp
7
3 8
8 1 0
2 7 4 4
4 5 2 6 5
```
在上面的样例中,从 $7 \to 3 \to 8 \to 7 \to 5$ 的路径产生了最大
## 输入格式
第一个行一个正整数 $r$ ,表示行的数目。
后面每行为这个数字金字塔特定行包含的整数。
## 输出格式
单独的一行,包含那个可能得到的最大的和。
## 样例 #1
### 样例输入 #1
```
5
7
3 8
8 1 0
2 7 4 4
4 5 2 6 5
```
### 样例输出 #1
```
30
```
## 提示
【数据范围】
对于 $100\%$ 的数据,$1\le r \le 1000$,所有输入在 $[0,100]$ 范围内。
题目翻译来自NOCOW。
USACO Training Section 1.5
IOI1994 Day1T1
逆向求解
若从倒数第二排的‘2’开始走,只有2个选择,往左下方和右下方。
往左下方是‘4’,得到的最终值为6,往右下方是‘5’,得到的最终值是7.这时当然选择右下方。
我们就将‘2’改写成2+5=7。 再次考虑倒数第二排的7,
同理,应选择左下,得到最终值是12。还是将‘7’改写成5+7=12。
#include
int max(int x,int y)
{
if(x>y) return x;
else return y;
}
int main()
{
int i,j,teap;
int n;
int a[1001][1001];
scanf("%d",&n);
for(i=1;i<=n;i++)
{
for(j=1;j<=i;j++)
{
scanf("%d",&a[i][j]);
}
}
for(i=n-1;i>=1;i--)
{
for(j=1;j<=i;j++)
{
teap=max(a[i+1][j],a[i+1][j+1]);
a[i][j]=a[i][j]+teap;
}
}
printf("%d",a[1][1]);
}
# 【模板】最长公共子序列
## 题目描述
给出 $1,2,\ldots,n$ 的两个排列 $P_1$ 和 $P_2$ ,求它们的最长公共子序列。
## 输入格式
第一行是一个数 $n$。
接下来两行,每行为 $n$ 个数,为自然数 $1,2,\ldots,n$ 的一个排列。
## 输出格式
一个数,即最长公共子序列的长度。
## 样例 #1
### 样例输入 #1
```
5
3 2 1 4 5
1 2 3 4 5
```
### 样例输出 #1
```
3
```
## 提示
- 对于 $50\%$ 的数据, $n \le 10^3$;
- 对于 $100\%$ 的数据, $n \le 10^5$。
动态规划
#include
int a[100001],b[100001];
int s[100001];
int dp[100001];
int max(int a,int b)
{
if(a>b) return a;
else return b;
}
int main()
{
int len=0;
int i,j;
int n;
scanf("%d",&n);
for(i=1;i<=n;i++)
{
scanf("%d",&a[i]);
s[a[i]]=i;
}
for(i=1;i<=n;i++)
{
scanf("%d",&b[i]);
b[i]=s[b[i]];//将上面的数的下标对应到下面的数来
//printf("%d ",b[i]);
}
//下面求b的最长递增子序列
for(i=1;i<=n;i++)
{
if(i==1)
{
len++;
dp[len]=b[i];
}
else
{
if(b[i]>dp[len])//大于就放进去,加后面
{
len++;
dp[len]=b[i];
}
else
{
j=len;
while(dp[j]>b[i]&&j>=1)
{
j--;
}
dp[j+1]=b[i];
}
}
}
printf("%d",len);
}
下班下班,上选修课都没时间学习了(;´༎ຶД༎ຶ`)