三倍经验
题目描述
数字金字塔由 n n n 行整数组成,第 i ( 1 ≤ i ≤ n ) i(1\le i\le n) i(1≤i≤n) 行有 i i i 个数字,一个示例如下。
7
3 9
8 1 0
2 7 4 4
4 5 2 6 5
现在你在金字塔的顶部(第一行),你希望走到金字塔的底部(第 n n n 行),每一步你只能走向当前所在位置的左下方的数字或者右下方的数字。同时作为一个强大的小朋友,你可以选择金字塔中的不多于 k k k 个数字让他们成为原来的 3 3 3 倍。
你会收集你路上经过的所有位置上的数字,最后的得分即为收集的数字之和,求最大得分。
输入格式
第一行输入两个整数
n
,
k
n,k
n,k,表示数字金字塔的行数和乘
3
3
3 的数字个数最大值;
接下来
n
n
n 行,其中的第
i
i
i 行有
i
i
i 个以空格隔开的整数依次表示数字金字塔第
i
i
i 行的数字
a
i
,
1
,
a
i
,
2
,
a
i
,
3
.
.
.
a
i
,
i
a_{i,1},a_{i,2},a_{i,3}...a_{i,i}
ai,1,ai,2,ai,3...ai,i。
输出格式
一行一个整数,表示最大得分。
样例 #1
样例输入 #1
5 3
7
3 9
8 1 0
2 7 4 4
4 5 2 6 5
样例输出 #1
75
提示
对于
30
%
30\%
30% 的数据,满足
k
≤
n
≤
6
k\le n\le 6
k≤n≤6,并且对于任意
1
≤
i
≤
n
1\le i\le n
1≤i≤n,
1
≤
j
≤
i
1\le j\le i
1≤j≤i 满足
0
≤
a
i
,
j
≤
100
0\le a_{i,j}\le 100
0≤ai,j≤100;
对于
100
%
100\%
100% 的数据,满足
1
≤
n
≤
100
1\le n\le100
1≤n≤100,
0
≤
k
≤
n
(
n
+
1
)
2
0\le k\le \dfrac{n(n+1)}{2}
0≤k≤2n(n+1),且对于任意
1
≤
i
≤
n
1\le i\le n
1≤i≤n,
1
≤
j
≤
i
1\le j\le i
1≤j≤i 满足
∣
a
i
,
j
∣
≤
1
0
9
|a_{i,j}|\le 10^9
∣ai,j∣≤109。
搜索过程:
根据有没有乘三倍的机会,分开搜索,然后再细分左边还是右边
1.越界直接return 0;
2.搜过当前状态,直接return
3.搜索
4.返回答案
#include<iostream>
#include<algorithm>
#include<cstring>
#include<string>
#include<cmath>
#define int long long
using namespace std;
int n, m;
int w[105][105];
int f[105][105][105];
bool st[150][150][150];
int dfs(int x, int y, int num)
{
if (x <= 0 || y <= 0 || x > n || y > x)
{
return 0;
}
if (st[x][y][num]) return f[x][y][num];
if (num) {
f[x][y][num] = max(f[x][y][num], dfs(x + 1, y, num - 1) + 3 * w[x][y]);
f[x][y][num] = max(f[x][y][num], dfs(x + 1, y + 1, num - 1) + 3 * w[x][y]);
}
f[x][y][num] = max(f[x][y][num], dfs(x + 1, y, num) + w[x][y]);
f[x][y][num] = max(f[x][y][num], dfs(x + 1, y + 1, num) + w[x][y]);
st[x][y][num] = 1;
return f[x][y][num];
}
signed main()
{
cin >> n >> m;
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= i; j++)
cin >> w[i][j];
}
memset(f, -0x7f, sizeof f);
cout << dfs(1, 1, m) << endl;
return 0;
}
[SHOI2002] 滑雪
题目描述
Michael 喜欢滑雪。这并不奇怪,因为滑雪的确很刺激。可是为了获得速度,滑的区域必须向下倾斜,而且当你滑到坡底,你不得不再次走上坡或者等待升降机来载你。Michael 想知道在一个区域中最长的滑坡。区域由一个二维数组给出。数组的每个数字代表点的高度。下面是一个例子:
1 2 3 4 5
16 17 18 19 6
15 24 25 20 7
14 23 22 21 8
13 12 11 10 9
一个人可以从某个点滑向上下左右相邻四个点之一,当且仅当高度会减小。在上面的例子中,一条可行的滑坡为 24 − 17 − 16 − 1 24-17-16-1 24−17−16−1(从 24 24 24 开始,在 1 1 1 结束)。当然 25 25 25- 24 24 24- 23 23 23- … \ldots …- 3 3 3- 2 2 2- 1 1 1 更长。事实上,这是最长的一条。
输入格式
输入的第一行为表示区域的二维数组的行数 R R R 和列数 C C C。下面是 R R R 行,每行有 C C C 个数,代表高度(两个数字之间用 1 1 1 个空格间隔)。
输出格式
输出区域中最长滑坡的长度。
样例 #1
样例输入 #1
5 5
1 2 3 4 5
16 17 18 19 6
15 24 25 20 7
14 23 22 21 8
13 12 11 10 9
样例输出 #1
25
提示
对于 100 % 100\% 100% 的数据, 1 ≤ R , C ≤ 100 1\leq R,C\leq 100 1≤R,C≤100。
#include<iostream>
#include<cstring>
#include<string>
#include<algorithm>
using namespace std;
int t, m,n;
int g[105][105];
int f[105][102];
int dx[] = { 1,0,-1,0 };
int dy[] = { 0,-1,0,1 };
int dp(int x, int y)
{
if (f[x][y] != -1) return f[x][y];
f[x][y] = 1;//保底有一个
for (int i = 0; i < 4; i++)
{
int xx = x + dx[i], yy = y + dy[i];
if (xx >= 1 &&xx <= n && yy >= 1 && yy <= m && g[x][y] > g[xx][yy])
f[x][y] = max(f[x][y], dp(xx, yy) + 1);
}
return f[x][y];
}
int main()
{
cin >> n >> m;
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= m; j++)
cin >> g[i][j];
}
memset(f, -1, sizeof f);
int res = 0;
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= m; j++)
res = max(res, dp(i, j));
}
cout << res << endl;
return 0;
}
[NOIP2012 普及组] 摆花
题目描述
小明的花店新开张,为了吸引顾客,他想在花店的门口摆上一排花,共 m m m 盆。通过调查顾客的喜好,小明列出了顾客最喜欢的 n n n 种花,从 1 1 1 到 n n n 标号。为了在门口展出更多种花,规定第 i i i 种花不能超过 a i a_i ai 盆,摆花时同一种花放在一起,且不同种类的花需按标号的从小到大的顺序依次摆列。
试编程计算,一共有多少种不同的摆花方案。
输入格式
第一行包含两个正整数 n n n 和 m m m,中间用一个空格隔开。
第二行有 n n n 个整数,每两个整数之间用一个空格隔开,依次表示 a 1 , a 2 , ⋯ , a n a_1,a_2, \cdots ,a_n a1,a2,⋯,an。
输出格式
一个整数,表示有多少种方案。注意:因为方案数可能很多,请输出方案数对 1 0 6 + 7 10^6+7 106+7 取模的结果。
样例 #1
样例输入 #1
2 4
3 2
样例输出 #1
2
提示
【数据范围】
对于 20 % 20\% 20% 数据,有 0 < n ≤ 8 , 0 < m ≤ 8 , 0 ≤ a i ≤ 8 0<n \le 8,0<m \le 8,0 \le a_i \le 8 0<n≤8,0<m≤8,0≤ai≤8。
对于 50 % 50\% 50% 数据,有 0 < n ≤ 20 , 0 < m ≤ 20 , 0 ≤ a i ≤ 20 0<n \le 20,0<m \le 20,0 \le a_i \le 20 0<n≤20,0<m≤20,0≤ai≤20。
对于 100 % 100\% 100% 数据,有 0 < n ≤ 100 , 0 < m ≤ 100 , 0 ≤ a i ≤ 100 0<n \le 100,0<m \le 100,0 \le a_i \le 100 0<n≤100,0<m≤100,0≤ai≤100。
NOIP 2012 普及组 第三题
#include<bits/stdc++.h>
#define int long long
using namespace std;
int w[105];
int f[105][155];
int ans;
int n,m;
int dfs(int x,int num)
{
int ans=0;//每次归零表示在当前状态下的方案数
if(num==m) return 1;//有方案就放前面
if(x>n||num>m) return 0;//一定是排除
if(f[x][num]) return f[x][num];//在记忆化
for(int i=0;i<=w[x];i++){
ans=(ans+dfs(x+1,num+i))%1000007;
}
f[x][num]=ans;//状态表示
return ans;//返回答案
}
signed main()
{
cin>>n>>m;
for(int i=1;i<=n;i++) cin>>w[i];
cout<<dfs(1,0)%1000007<<endl;
}
没有上司的舞会
题目描述
某大学有 n n n 个职员,编号为 1 … n 1\ldots n 1…n。
他们之间有从属关系,也就是说他们的关系就像一棵以校长为根的树,父结点就是子结点的直接上司。
现在有个周年庆宴会,宴会每邀请来一个职员都会增加一定的快乐指数 r i r_i ri,但是呢,如果某个职员的直接上司来参加舞会了,那么这个职员就无论如何也不肯来参加舞会了。
所以,请你编程计算,邀请哪些职员可以使快乐指数最大,求最大的快乐指数。
输入格式
输入的第一行是一个整数 n n n。
第 2 2 2 到第 ( n + 1 ) (n + 1) (n+1) 行,每行一个整数,第 ( i + 1 ) (i+1) (i+1) 行的整数表示 i i i 号职员的快乐指数 r i r_i ri。
第 ( n + 2 ) (n + 2) (n+2) 到第 2 n 2n 2n 行,每行输入一对整数 l , k l, k l,k,代表 k k k 是 l l l 的直接上司。
输出格式
输出一行一个整数代表最大的快乐指数。
样例 #1
样例输入 #1
7
1
1
1
1
1
1
1
1 3
2 3
6 4
7 4
4 5
3 5
样例输出 #1
5
提示
数据规模与约定
对于 100 % 100\% 100% 的数据,保证 1 ≤ n ≤ 6 × 1 0 3 1\leq n \leq 6 \times 10^3 1≤n≤6×103, − 128 ≤ r i ≤ 127 -128 \leq r_i\leq 127 −128≤ri≤127, 1 ≤ l , k ≤ n 1 \leq l, k \leq n 1≤l,k≤n,且给出的关系一定是一棵树。
#include<iostream>
#include<cstring>
#include<string>
#include<algorithm>
#include<vector>
using namespace std;
int w[6005];
int n;
bool vis[6005];
vector<int>ans[6005];
int f[6005][5];
int dfs(int x,bool go){
if (!ans[x].size()) return w[x] * go;
if (f[x][go]) return f[x][go];
int res = 0;
if (go)
{
for (int i = 0; i < ans[x].size(); i++)
{
res += dfs(ans[x][i], 0);
}
}
else
{
for (int i = 0; i < ans[x].size(); i++)
{
res += max(dfs(ans[x][i], 1),dfs(ans[x][i],0));
}
}
if (go) return f[x][go]=res + w[x];
else return f[x][go]=res;//边return边记忆化
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin >> n;
for (int i = 1; i <= n; i++) cin >> w[i];
for (int i = 1; i <= n - 1; i++)
{
int a, b;
cin >> a >> b;
ans[b].push_back(a);
vis[a] = 1;
}
for (int i = 1; i <= n; i++)
{
if (!vis[i])
cout << max(dfs(i, 1), dfs(i, 0));//从头搜
}
return 0;
}