zoukankan      html  css  js  c++  java
  • Copying Books

    Copying Books

    给出一个长度为m的序列({a_i}),将其划分成k个区间,求区间和的最大值的最小值对应的方案,多种方案,则按从左到右的区间长度尽可能小(也就是从左到右区间长度构成的序列的字典序最小),(m,kleq 500)

    显然最大值的最小值想到二分,其实dp也可以,因为区间划分问题有可递推性,而且它能求出答案。

    二分一个东西就等于换时间复杂度增加个(log(n))增加了一个已知条件,虽然前提是单调性,但不妨以后缺少条件,先考虑二分再找单调性。

    我们二分(x)表示区间和的最大值不超过(x),于是二分以后再考虑贪心(说是在的,二分后面的check要么是贪心要么是dp),那么从左往右扫描,处理出一个区间时,不停地在它的右边增加数字,当刚好要超过的时候,就把该个数字划分到下一个区间,显然这样我们得到了一个数字,意思即满足当前条件下最少的区间数。

    其实可以看成一个函数(f(x)),显然随着x的增大,最少区间数会减少,而x又恰恰对应一个范围([f(x),n]),即区间数的范围。

    因此当k在这个范围外的时候,显然(f(x))需要减少,即x增加,反之(应该写的是(lower\_bound)二分),于是我们就得到了一个最小的x,正好框住k,显然当取比x大的值,同样满足条件,但是结果不优秀,取比x小的又不满足条件,于是x就是答案的"前提"。

    于是按照之前的贪心方法,可以得到一个方案,字典序最小,只要从右往左贪心即可,但它是最少的区间数的方案,于是还得随便砍掉一些区间,显然可以随便砍,又要保证字典序最小,于是从左往右扫描,能砍就砍,最终时间复杂度O(mlog(m))。

    参考代码:

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #define il inline
    #define ri register
    #define Size 550
    using namespace std;
    bool b[Size];
    int a[Size],m;
    il void read(int&);
    il int fen(int);
    int main(){
    	//freopen("in","r",stdin);
    	int lsy;read(lsy);
    	while(lsy--){
    		memset(b,0,sizeof(b));
    		int k,l(0),r(0);read(m),read(k);
    		for(int i(1);i<=m;++i)
    			read(a[i]),r+=a[i],l=max(l,a[i]);
    		int mid;while(l<=r){
    			mid=l+r>>1;
    			if(fen(mid)>k)l=mid+1;
    			else r=mid-1;
    		}int tot(1);
    		for(int i(m),j(0);i;--i)
    			if(j+a[i]<=l)j+=a[i];
    			else j=a[i],b[i]=1,++tot;
    		tot=k-tot;
    		for(int i(1);i<=m;++i)
    		  if(tot&&!b[i])b[i]=1,--tot;
    		for(int i(1);i<=m;++i){
    			printf("%d ",a[i]);
    			if(b[i])printf("/ ");
    		}
    		putchar('
    ');
    	}
    	return 0;
    }
    il int fen(int x){int ans(1);
    	for(int i(1),j(0);i<=m;++i)
    		if(j+a[i]<=x)j+=a[i];
    		else j=a[i],++ans;
    	return ans;
    }
    il void read(int &x){
    	x^=x;ri char c;while(c=getchar(),c<'0'||c>'9');
    	while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+(c^48),c=getchar();
    }
    
  • 相关阅读:
    LeetCode-1-two-sum
    LeetCode-14-longest-common-prefix
    动态规划--矩阵链乘法
    动态规划--装配线调度算法
    LeetCode-9-palindrome-number
    LeetCode-8-string-to-integer-atoi
    LeetCode-7-Reverse Integer
    SElinux用户管理操作
    Minix3信号处理分析
    面对困难
  • 原文地址:https://www.cnblogs.com/a1b3c7d9/p/11403105.html
Copyright © 2011-2022 走看看