【2015-2016 XVI Open CupD】【ST-RMQ】dir -C 文件划分成最少的行

D. dir -C
time limit per test
1 second
memory limit per test
256 megabytes
input
standard input
output
standard output

Famous Berland coder and IT manager Linus Gates announced his next proprietary open-source system "Winux 10.04 LTS"

In this system command "dir -C" prints list of all files in the current catalog in multicolumn mode.

Lets define the multicolumn mode for number of lines l. Assume that filenames are already sorted lexicographically.

  • We split list of filenames into several continuous blocks such as all blocks except for maybe last one consist of l filenames, and last block consists of no more than l filenames, then blocks are printed as columns.
  • Width of each column wi is defined as maximal length of the filename in appropriate block.
  • Columns are separated by 1 × l column of spaces.
  • So, width of the output is calculated as , i.e. sum of widths of each column plus number of columns minus one.

Example of multi-column output:

a       accd e t
aba     b    f wtrt
abacaba db   k

In the example above width of output is equal to 19.

"dir -C" command selects minimal l, such that width of the output does not exceed width of screen w.

Given information about filename lengths and width of screen, calculate number of lines l printed by "dir -C" command.

Input

First line of the input contains two integers n and w — number of files in the list and width of screen (1 ≤ n ≤ 105, 1 ≤ w ≤ 109).

Second line contains n integers fi — lengths of filenames. i-th of those integers represents length of i-th filename in the lexicographically ordered list (1 ≤ fi ≤ w).

Output

Print one integer — number of lines l, printed by "dir -C" command.

Examples
input
11 20
1 3 7 4 1 2 1 1 1 1 4
output
3


#include<stdio.h>
#include<iostream>
#include<string.h>
#include<string>
#include<ctype.h>
#include<math.h>
#include<set>
#include<map>
#include<vector>
#include<queue>
#include<bitset>
#include<algorithm>
#include<time.h>
using namespace std;
void fre() { freopen("c://test//input.in", "r", stdin); freopen("c://test//output.out", "w", stdout); }
#define MS(x,y) memset(x,y,sizeof(x))
#define MC(x,y) memcpy(x,y,sizeof(x))
#define MP(x,y) make_pair(x,y)
#define ls o<<1
#define rs o<<1|1
typedef long long LL;
typedef unsigned long long UL;
typedef unsigned int UI;
template <class T1, class T2>inline void gmax(T1 &a, T2 b) { if (b>a)a = b; }
template <class T1, class T2>inline void gmin(T1 &a, T2 b) { if (b<a)a = b; }
const int N = 1e5+10, M = 0, Z = 1e9 + 7, ms63 = 0x3f3f3f3f;
int n, w;
int b[20];
int a[N];
int f[18][N];
void RMQinit()
{
	int L = log(n + 0.5) / log(2.0);
	for (int j = 1; j <= n; ++j)f[0][j] = a[j];
	for (int i = 1; i <= L; ++i)
	{
		int len = b[i - 1] - 1;
		for (int j = 1; j + len <= n; ++j)
		{
			f[i][j] = max(f[i - 1][j], f[i - 1][j + len + 1]);
		}
	}
}

int check(int l, int r)
{
	int len = r - l + 1;
	int k = log(len + 0.5) / log(2.0);
	return max(f[k][l], f[k][r - b[k] + 1]);
}

int solve()
{
	for (int i = 1; i <= n; ++i)//枚举行数
	{
		int l = 1;
		int r = i;
		int tmp = 0;
		while (1)
		{
			tmp += check(l, r) + 1;
			if (tmp > w)break;
			if (r == n)break;
			l += i;
			r += i;
			if (r >= n)r = n;
		}
		if (tmp <= w)return i;
	}
}
int main()
{
	for (int i = 0; i < 20; ++i)b[i] = 1 << i;
	while (~scanf("%d%d", &n,&w))
	{
		++w;
		for (int i = 1; i <= n; ++i)scanf("%d", &a[i]);
		RMQinit();
		printf("%d\n", solve());
	}
	return 0;
}
/*
【trick&&吐槽】
1,分析样例理解题意往往是最行之有效的方法
2,ST的预处理是O(nlogn),查询是O(1),复杂度不要搞错了

【题意】
文件的个数为n(1e5)个,
屏幕的宽度为w[1, 1e9]
每个文件有一个文件名,文件名有长度f[],f[]为[1, w]的数

我们把文件名列表,用尽可能少的行l输出。
我们竖着排版,除了最后一列,其它列的文件数都为l,
每一列的长度为为其中最长文件名长度(+1个空格如果不是在最后一列)

【类型】
ST-RMQ

【分析】
首先, 直接线段树可以在O(nlognlogn)的复杂度内解决本题。
然后,这题是不能二分的。行数多了,可能还放不下。
于是我们暴力,从行数为1开始,枚举行数。
接下来用logn的复杂度验证当行数为l时的可行性。

在思考过程中,我以为ST表的复杂度为log,然而其为O(1)
所以,我直接用ST表就可以在O(nlogn)的整体复杂度内AC这道题。

细节上是怎样呢?
当行数为l时,第[1,l]取max作为第一列列宽,
第[l+1,2l]取max作为第二列列宽,
依次类推……

当l=1时,有n/1列,有n/1个查询
当l=2时,有n/2列,有n/2个查询
所以总的查询数为nlogn
所以总的复杂度为O(nlogn)

【时间复杂度&&优化】
O(nlogn)

*/



你可能感兴趣的:(codeforces,题库-CF,ST-RMQ)