尼克每天上班之前都连接上英特网,接收他的上司发来的邮件,这些邮件包含了尼克主管的部门当天要完成的全部任务,每个任务由一个开始时刻与一个持续时间构成。
尼克的一个工作日为 n n n 分钟,从第 1 1 1 分钟开始到第 n n n 分钟结束。当尼克到达单位后他就开始干活,公司一共有 k k k 个任务需要完成。如果在同一时刻有多个任务需要完成,尼克可以任选其中的一个来做,而其余的则由他的同事完成,反之如果只有一个任务,则该任务必需由尼克去完成,假如某些任务开始时刻尼克正在工作,则这些任务也由尼克的同事完成。如果某任务于第 p p p 分钟开始,持续时间为 t t t 分钟,则该任务将在第 ( p + t − 1 ) (p+t-1) (p+t−1) 分钟结束。
写一个程序计算尼克应该如何选取任务,才能获得最大的空暇时间。
输入数据第一行含两个用空格隔开的整数 n n n 和 k k k。
接下来共有 k k k 行,每一行有两个用空格隔开的整数 p p p 和 t t t,表示该任务从第 p p p 分钟开始,持续时间为 t t t 分钟。
输出文件仅一行,包含一个整数,表示尼克可能获得的最大空暇时间。
15 6
1 2
1 6
4 11
8 5
8 1
11 5
4
N = 10010
f = [0] * N
a = [[] for _ in range(N)] #存储i时刻的任务情况
n, m = map(int, input().split())
for i in range(m) :
s, l = map(int, input().split())
a[s].append(l)
for i in range(n, 0, -1) : #遍历时刻与背包
length = len(a[i])
if length == 0 :
f[i] = f[i + 1] + 1
else :
for j in a[i] :
f[i] = max(f[i], f[i + j])
print(f[1])
建筑大师最近在跟着数学大师 ljt12138 学数学,今天他学了等差数列,ljt12138 决定给他留一道练习题。
ljt12138 首先建了 n n n 个特斯拉电磁塔,这些电塔排成一排,从左到右依次标号为 1 1 1 到 n n n,第 i i i 个电塔的高度为 h [ i ] h[i] h[i]。
建筑大师需要从中选出一些电塔,然后这些电塔就会缩到地下去。这时候,如果留在地上的电塔的高度,从左向右构成了一个等差数列,那么这个选择方案就会被认为是美观的。
建筑大师需要求出,一共有多少种美观的选择方案,答案模 998244353 998244353 998244353。
注意,如果地上只留了一个或者两个电塔,那么这种方案也是美观的。地上没有电塔的方案被认为是不美观的。
同时也要注意,等差数列的公差也可以为负数。
第一行一个正整数 n n n。
第二行 n n n 个非负整数,第 i i i 个整数是第 i i i 个电塔的高度 h [ i ] h[i] h[i]。
输出一个整数,表示美观的方案数模 998244353 998244353 998244353 的值。
8
13 14 6 20 27 34 34 41
50
100
90 1004 171 99 1835 108 81 117 141 126 135 144 81 153 193 81 962 162 1493 171 1780 864 297 180 532 1781 189 1059 198 333 1593 824 207 1877 216 270 225 1131 336 1875 362 234 81 288 1550 243 463 1755 252 406 261 270 279 288 1393 261 1263 297 135 333 872 234 881 180 198 81 225 306 180 90 315 81 81 198 252 81 297 1336 1140 1238 81 198 297 661 81 1372 469 1132 81 126 324 333 342 81 351 481 279 1770 1225 549
11153
设 v v v 为最高的电塔高度。
对于前 30 % 30\% 30% 的数据,$n \le 20 $。
对于前 60 % 60\% 60% 的数据, n ≤ 100 n \le 100 n≤100, v ≤ 2 × 1 0 3 v \le 2 \times 10^3 v≤2×103。
对于另外 20 % 20\% 20% 的数据,所有电塔的高度构成一个等差数列。
对于 100 % 100\% 100% 的数据, n ≤ 1 0 3 n \le 10^3 n≤103, v ≤ 2 × 1 0 4 v \leq2 \times 10^4 v≤2×104。
题目要求序列中存在等差数列的数量,可以利用类似于最长上升子序列来进行状态表示和状态计算。
状态表示:f[i, j]
集合:表示以i结尾且公差为j的等差数列的集合
属性:num
状态计算: if nums[i] - nums[k] == j : f[i, j] += (f[k, j] + 1),=>f[i, nums[i] - nums[k]] += (f[k, nums[i] - nums[k]] + 1)
N = 1010
MOD = 998244353
shift = 20010
f = [[1] * shift * 2 for _ in range(N)] #单个数可以是任意等差数列,记为一个方案
nums = [0] * N
n = int(input())
nums[1 : n + 1] = list[map(int, input().split())]
ans = n #初始化为单个数等差数列方案数
# 最长上升子序列模板
for i in range(2, n + 1) :
for j in range(1, i) :
equ = nums[i] - nums[j]
f[i][equ + shift] = (f[i][equ + shift] + f[j][equ + shift]) % MOD
ans = (ans + f[j][equ + shift]) % MOD
print(ans)
一堆木头棍子共有n根,每根棍子的长度和宽度都是已知的。棍子可以被一台机器一个接一个地加工。机器处理一根棍子之前需要准备时间。准备时间是这样定义的:
第一根棍子的准备时间为1分钟;
如果刚处理完长度为L,宽度为W的棍子,那么如果下一个棍子长度为Li,宽度为Wi,并且满足L>=Li,W>=Wi,这个棍子就不需要准备时间,否则需要1分钟的准备时间;
计算处理完n根棍子所需要的最短准备时间。比如,你有5根棍子,长度和宽度分别为(4, 9),(5, 2),(2, 1),(3, 5),(1, 4),最短准备时间为2(按(4, 9)、(3, 5)、(1, 4)、(5, 2)、(2, 1)的次序进行加工)。
第一行是一个整数n(n<=5000),第2行是2n个整数,分别是L1,W1,L2,w2,…,Ln,Wn。L和W的值均不超过10000,相邻两数之间用空格分开。
仅一行,一个整数,所需要的最短准备时间。
5
4 9 5 2 2 1 3 5 1 4
2
如果下一个棍子长度为Li,宽度为Wi,并且满足L>=Li,W>=Wi,这个棍子就不需要准备时间,否则需要1分钟的准备时间
即求出长度和宽度共同的不上升子序列划分最少,按照dilworth定理可知,即求最大上升子序列。对于本题的二维数据,需要使用一点贪心的思维,因为两维都要求不上升,那么先让第一维按照降序排序,其次再让第二维按照降序排序,最后使用最长上升子序列模型
N = 5010
f = [1] * N
nums = []
n = int(input())
tmp = list(map(int, input().split()))
for i in range(n) :
nums.append([tmp[i * 2], tmp[i * 2 + 1]])
nums.sort(reverse = True)
res = 1
for i in range(1, n + 1) :
for j in range(1, i) :
if nums[i - 1][1] > nums[j - 1][1] :
f[i] = max(f[i], f[j] + 1)
res = max(res, f[i])
print(res)
线性dp一般大致分为序列问题和背包问题,要熟练掌握数字三角形、最长上升子序列模型等
某一村庄在一条路线上安装了 n n n 盏路灯,每盏灯的功率有大有小(即同一段时间内消耗的电量有多有少)。老张就住在这条路中间某一路灯旁,他有一项工作就是每天早上天亮时一盏一盏地关掉这些路灯。
为了给村里节省电费,老张记录下了每盏路灯的位置和功率,他每次关灯时也都是尽快地去关,但是老张不知道怎样去关灯才能够最节省电。他每天都是在天亮时首先关掉自己所处位置的路灯,然后可以向左也可以向右去关灯。开始他以为先算一下左边路灯的总功率再算一下右边路灯的总功率,然后选择先关掉功率大的一边,再回过头来关掉另一边的路灯,而事实并非如此,因为在关的过程中适当地调头有可能会更省一些。
现在已知老张走的速度为 1 m / s 1m/s 1m/s,每个路灯的位置(是一个整数,即距路线起点的距离,单位: m m m)、功率( W W W),老张关灯所用的时间很短而可以忽略不计。
请你为老张编一程序来安排关灯的顺序,使从老张开始关灯时刻算起所有灯消耗电最少(灯关掉后便不再消耗电了)。
第一行是两个数字 n n n(表示路灯的总数)和 c c c(老张所处位置的路灯号);
接下来 n n n 行,每行两个数据,表示第 1 1 1 盏到第 n n n 盏路灯的位置和功率。数据保证路灯位置单调递增。
一个数据,即最少的功耗(单位: J J J, 1 J = 1 W × s 1J=1W\times s 1J=1W×s)。
5 3
2 10
3 20
5 20
6 30
8 10
270
此时关灯顺序为 3 4 2 1 5
。
1 ≤ n ≤ 50 1\le n\le50 1≤n≤50, 1 ≤ c ≤ n 1\le c\le n 1≤c≤n。
一道很好的区间dp+状态机的问题
老张关掉一个灯后,有两种选择,1、继续沿着上次的方向关灯,2、向着相反方向关灯
老张走过的路上的灯一定被关掉,所以老张关灯的过程就是一个区间扩大的过程。
从集合的角度思考:
状态表示f[l, r, 0], f[l, r, 1]:
集合:l~r区间的灯被关,且最终老张位于左边0、右边1所用时间的集合
属性:min
状态计算:
f[l, r, 0] = min(f[l + 1, r, 0] + path[l + 1 ~ l], f[l + 1, r, 1] + path[r ~ l])
f[l, r, 1] = min(f[l, r - 1, 1] + path[r - 1~r], f[l, r - 1, 0] + path[l ~ r])
N = 55
INF = 100010
f = [[[INF] * 2 for _ in range(N)] for _ in range(N)]
path = [0] * N
energe = [0] * N
n, m = map(int, input().split())
for i in range(1, n + 1) :
p, e = map(int, input().split())
energe[i] += (energe[i - 1] + e)
path[i] = p
f[m][m] = [0, 0]
for length in range(2, n + 1) :
for l in range(1, n + 1) :
r = l + length - 1
if r > n : break
left, right = energe[l] + energe[n] - energe[r], energe[l - 1] + energe[n] - energe[r - 1]
f[l][r][0] = min(f[l + 1][r][0] + left * (path[l + 1] - path[l]), f[l + 1][r][1] + left * (path[r] - path[l]))
f[l][r][1] = min(f[l][r - 1][1] + right * (path[r] - path[r - 1]), f[l][r - 1][0] + right * (path[r] - path[l]))
print(min(f[1][n][0], f[1][n][1]))
帅帅经常跟同学玩一个矩阵取数游戏:对于一个给定的 n × m n \times m n×m 的矩阵,矩阵中的每个元素 a i , j a_{i,j} ai,j 均为非负整数。游戏规则如下:
帅帅想请你帮忙写一个程序,对于任意矩阵,可以求出取数后的最大得分。
输入文件包括 n + 1 n+1 n+1 行:
第一行为两个用空格隔开的整数 n n n 和 m m m。
第 2 ∼ n + 1 2\sim n+1 2∼n+1 行为 n × m n \times m n×m 矩阵,其中每行有 m m m 个用单个空格隔开的非负整数。
输出文件仅包含 1 1 1 行,为一个整数,即输入矩阵取数后的最大得分。
2 3
1 2 3
3 4 2
82
【数据范围】
对于 60 % 60\% 60% 的数据,满足 1 ≤ n , m ≤ 30 1\le n,m\le 30 1≤n,m≤30,答案不超过 1 0 16 10^{16} 1016。
对于 100 % 100\% 100% 的数据,满足 1 ≤ n , m ≤ 80 1\le n,m\le 80 1≤n,m≤80, 0 ≤ a i , j ≤ 1000 0\le a_{i,j}\le1000 0≤ai,j≤1000。
【题目来源】
NOIP 2007 提高第三题。
n, m = map(int, input().split())
res = 0
for i in range(n) :
nums = list(map(int, input().split()))
f = [[0] * (m + 1) for i in range(m + 1)]
for length in range(1, m + 1) :
for l in range(1, m + 1) :
r = l + length - 1
if r > m : break
if length == 1 :
f[l][r] = nums[l - 1] * 2 ** m
else :
left, right = nums[l - 1] * 2 ** (m - length + 1), nums[r - 1] * 2 ** (m - length + 1)
f[l][r] = max(f[l + 1][r] + left, f[l][r - 1] + right)
res += f[1][m]
print(res)
Bessie likes downloading games to play on her cell phone, even though she doesfind the small touch screen rather cumbersome to use with her large hooves.
She is particularly intrigued by the current game she is playing.The game starts with a sequence of N N N positive integers ( 2 ≤ N ≤ 248 2 \leq N\leq 248 2≤N≤248), each in the range 1 … 40 1 \ldots 40 1…40. In one move, Bessie cantake two adjacent numbers with equal values and replace them a singlenumber of value one greater (e.g., she might replace two adjacent 7swith an 8). The goal is to maximize the value of the largest numberpresent in the sequence at the end of the game. Please help Bessiescore as highly as possible!
给定一个1*n的地图,在里面玩2048,每次可以合并相邻两个(数值范围1-40),问序列中出现的最大数字的值最大是多少。注意合并后的数值并非加倍而是+1,例如2与2合并后的数值为3。
The first line of input contains N N N, and the next N N N lines give the sequence
of N N N numbers at the start of the game.
Please output the largest integer Bessie can generate.
4
1
1
1
2
3
In this example shown here, Bessie first merges the second and third 1s to
obtain the sequence 1 2 2, and then she merges the 2s into a 3. Note that it is
not optimal to join the first two 1s.
N = 250
a = [0] * N
f = [[0] * N for _ in range(N)]
ans = 0
n = int(input())
for i in range(1, n + 1) :
a[i] = int(input())
for length in range(1, n + 1) :
for l in range(1, n + 1) :
r = l + length - 1
if r > n : break
if length == 1 :
f[l][r] = a[l]
else :
for k in range(l, r) :
if f[l][k] == f[k + 1][r] :
f[l][r] = max(f[l][r], f[l][k] + 1)
ans = max(ans, f[l][r])
print(ans)
假设你有一条长度为 5 5 5 的木板,初始时没有涂过任何颜色。你希望把它的 5 5 5 个单位长度分别涂上红、绿、蓝、绿、红色,用一个长度为 5 5 5 的字符串表示这个目标: RGBGR \texttt{RGBGR} RGBGR。
每次你可以把一段连续的木板涂成一个给定的颜色,后涂的颜色覆盖先涂的颜色。例如第一次把木板涂成 RRRRR \texttt{RRRRR} RRRRR,第二次涂成 RGGGR \texttt{RGGGR} RGGGR,第三次涂成 RGBGR \texttt{RGBGR} RGBGR,达到目标。
用尽量少的涂色次数达到目标。
输入仅一行,包含一个长度为 n n n 的字符串,即涂色目标。字符串中的每个字符都是一个大写字母,不同的字母代表不同颜色,相同的字母代表相同颜色。
仅一行,包含一个数,即最少的涂色次数。
AAAAA
1
RGBGR
3
40 % 40\% 40% 的数据满足 1 ≤ n ≤ 10 1\le n\le 10 1≤n≤10。
100 % 100\% 100% 的数据满足 1 ≤ n ≤ 50 1\le n\le 50 1≤n≤50。
本题代码正确,但在洛谷Python无法通过,可以转为cpp
N = 55
f = [[N] * N for _ in range(N)]
a = input()
n = len(a)
for length in range(1, n + 1) :
for l in range(1, n + 1) :
r = l + length - 1
if r > n : break
if length == 1 :
f[l][r] = 1
else :
if a[l - 1] == a[r - 1] :
f[l][r] = min(f[l + 1][r], f[l][r - 1])
else :
for k in range(l, r) :
f[l][r] = min(f[l][r], f[l][k] + f[k + 1][r])
print(f[1][n])
cpp代码
#include
#include
#include
using namespace std;
const int N = 55;
int f[N][N];
string a;
int n;
int main() {
cin >> a;
n = a.length();
memset(f, 0x7f, sizeof(f));
for(int length = 1; length <= n; length ++) {
for (int l = 1; l + length - 1 <= n; l ++) {
int r = l + length - 1;
if (length == 1) f[l][r] = 1;
else if (a[l - 1] == a[r - 1]) f[l][r] = min(f[l + 1][r], f[l][r - 1]);
else {
for(int k = l; k < r; k ++) f[l][r] = min(f[l][r], f[l][k] + f[k + 1][r]);
}
}
}
cout << f[1][n] << endl;
return 0;
}
题目描述
Genos最近在他的手机上下载了祖玛游戏。在祖玛游戏里,存在n个一行的宝石,第i个宝石的颜色是Ci 。这个游戏的目标是尽快的消灭一行中所有的宝石。 在一秒钟,Genos能很快的挑选出这些有颜色的宝石中的一个回文的,连续的子串,并将这个子串移除。每当一个子串被删除后,剩余的宝石将连接在一起,形成一个新的行列。你的任务是:求出把整个宝石串都移除的最短时间。 让我们给你一个提示:如果一个串正着读或倒着读都一样,那么这个串(或子串)叫回文串。在我们这道题中,“回文”指这个宝石串中的第一个珠子的颜色等于最后一个珠子的颜色,第二个珠子的颜色等于倒数第二个珠子的颜色,等等。
输入输出格式
输入格式:
第一行包含一个整数n(1<=n<=500) ——宝石串的长度。 第二行包含n个被空格分开的整数,第i(1<=i<=n) 个表示这行中第i个珠子的颜色。
输出格式:
输出一个整数,把这行珠子移除的最短时间。 (样例略)
说明:
在第一个例子中,Genos可以在一秒钟就把这行珠子全部移走。 在第二个例子中,Genos一次只能移走一个珠子,所以移走三个珠子花费他三秒。 在第三个例子中,为了达到2秒的最快时间,先移除回文串4 4,再移除回文串1 2 3 2 1。
感谢@Administrator2004 提供的翻译
Genos recently installed the game Zuma on his phone. In Zuma there exists a line of $ n $ gemstones, the $ i $ -th of which has color $ c_{i} $ . The goal of the game is to destroy all the gemstones in the line as quickly as possible.
In one second, Genos is able to choose exactly one continuous substring of colored gemstones that is a palindrome and remove it from the line. After the substring is removed, the remaining gemstones shift to form a solid line again. What is the minimum number of seconds needed to destroy the entire line?
Let us remind, that the string (or substring) is called palindrome, if it reads same backwards or forward. In our case this means the color of the first gemstone is equal to the color of the last one, the color of the second gemstone is equal to the color of the next to last and so on.
The first line of input contains a single integer $ n $ ( $ 1<=n<=500 $ ) — the number of gemstones.
The second line contains $ n $ space-separated integers, the $ i $ -th of which is $ c_{i} $ ( $ 1<=c_{i}<=n $ ) — the color of the $ i $ -th gemstone in a line.
Print a single integer — the minimum number of seconds needed to destroy the entire line.
3
1 2 1
1
3
1 2 3
3
7
1 4 4 2 3 2 1
2
In the first sample, Genos can destroy the entire line in one second.
In the second sample, Genos can only destroy one gemstone at a time, so destroying three gemstones takes three seconds.
In the third sample, to achieve the optimal time of two seconds, destroy palindrome 4 4 first and then destroy palindrome 1 2 3 2 1.
N = 510
f = [[N] * N for _ in range(N)]
a = [0] * N
n = int(input())
a[1 : n + 1] = list(map(int, input().split()))
for length in range(1, n + 1) :
for l in range(1, n + 1) :
r = l + length - 1
if r > n : break
if length == 1 :
f[l][r] = 1
elif length == 2 :
if a[l] == a[r] :
f[l][r] = 1
else :
f[l][r] = 2
elif a[l] == a[r] :
f[l][r] = f[l + 1][r - 1]
else :
for k in range(l, r) :
f[l][r] = min(f[l][r], f[l][k] + f[k + 1][r])
print(f[1][n])