[vijos1246]文科生的悲哀(二)

[vijos1246]文科生的悲哀(二)

试题描述

化学不及格的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;
}

 

posted @ 2017-04-15 14:54  xjr01  阅读(488)  评论(0编辑  收藏  举报