试题描述
化学不及格的Matrix67无奈选择了文科。他必须硬着头皮艰难地进行着文科的学习。
这学期的政治、历史和地理课本各有n章。每一科的教学必须按章节从前往后依次进行。若干章政治、若干章历史和若干章的地理内容可以合成一个教学阶段。年级计划将整个学期的内容分成若干个阶段进行教学。为了保证各科教学进度相同,年级规定每一个阶段包含的各科的章节数必须相同。一个阶段包含的章节越多,这个阶段所需要的课时也就越多。经过研究,假如某个阶段包含政史地各k章,则政治学习需要花费3^k天的课时,历史学习需要花费5^k天的课时,地理学习需要花费2^k天的课时,最后还需要4天的综合训练。一个阶段所花费的总时间是以上四项时间的和。
为了便于安排时间,学校希望每个阶段恰好需要若干周来完成。因此,划分出的每一个阶段所需要的天数都必须是7的整数倍(高三是没有星期六和星期天的)。
那么,这学期的课程最多可以划分成多少个阶段呢?你会想到,要想划分的阶段数最多,一个阶段完成一章的任务就行了(因为3^1+5^1+2^1+4=14是7的整数倍)。但问题没有这么简单。每个课本都可能有一些独立性较强的连续章节,它们具有很强的连续性,必须在一个阶段中完成。如果你已知所有不能划分在两个或两个以上的阶段中的连续章节,你还能计算出最多能安排多少个阶段吗?
输入
第一行有两个用空格隔开的正整数n和m,分别表示各科课本的章节数和不可分割的连续章节的个数。
第二行到第m+1行,每行告诉了一个信息,该信息说明了哪一个课本的第几章到第几章必须一次性完成。同一科目给定的章节有可能重复或有重叠。
每一行信息分为两个部分。第一部分是“Politics:”、“History:”、“Geography:”三个字符串中的一个;第二部分是用“-”连接的两个数字x,y(1<=x<y<=n),表示该行第一部分所示的课本从第x章到第y章具有连续性。第二部分紧接在第一部分后面,没有任何符号分隔。
对于30%的数据,n,m<=10;
对于50%的数据,n,m<=1000;
对于100%的数据,n,m<=100 000。
输出
一个正整数,表示按照学校和年级的种种要求(见下)最多可以安排的阶段个数。
如果没有符合条件的安排方案,请输出-1。
注意:以下三个要求需要同时考虑。
1\.每一个阶段包含的各科章数相同;
2\.按时间函数计算出的各阶段所需天数必须是7的倍数;
3\.给出的任一个连续章节都不能被分割开来。
输入示例
8 3 Politics:1-2 History:5-6 Politics:1-4
输出示例
3
数据规模及约定
见“输入”
题解
首先打个表发现 (2k + 3k + 5k + 4) mod 7 是有循环节的,循环节长度为 6,并且在 0,1 和 2 的时候等于 0。
根据题意,三个科目可以压成一个科目,我们维护每一个被捆在一块的章节的大小,然后 dp 即可。令 f(i, j) 表示考虑前 i 块,最后一个阶段中所有块的大小总和 mod 6 = j 时最多分成的阶段个数,转移显然。
#include <iostream> #include <cstdio> #include <cstdlib> #include <cstring> #include <cctype> #include <algorithm> using namespace std; int read() { int x = 0, f = 1; char c = getchar(); while(!isdigit(c)){ if(c == ‘-‘) f = -1; c = getchar(); } while(isdigit(c)){ x = x * 10 + c - ‘0‘; c = getchar(); } return x * f; } #define maxn 100010 int f[maxn][10], val[maxn], A[maxn], cnt; void up(int& a, int b) { a = max(a, b); return ; } int main() { int n = read(), m = read(); while(m--) { int l = read(), r = read(); val[l]++; val[r]--; } int tag = 0; cnt = 1; for(int i = 1; i <= n; i++) { tag += val[i]; A[cnt]++; if(!tag) cnt++; } cnt--; memset(f, -1, sizeof(f)); f[0][0] = 0; for(int i = 0; i < cnt; i++) for(int j = 0; j < 6; j++) if(f[i][j] >= 0) { up(f[i+1][(j+A[i+1])%6], f[i][j]); if(j < 3) up(f[i+1][A[i+1]%6], f[i][j] + 1); } int ans = -1; for(int i = 0; i < 3; i++) up(ans, f[cnt][i]); printf("%d\n", ans); return 0; }