UVALive 6190

来源:互联网 发布:磷酸根机器数据怎么看 编辑:程序博客网 时间:2024/06/16 12:39

这道题卡了我们整场,我们想到了二分答案+判断可行性,但是卡在判断可行性上了,首先n^2的复杂度是肯定不行的,正解要优化到O(n)

dp[i]表示以第i个单词作为一行结尾是否可行,初始化dp[0]=1,然后是一个迭代的过程,由dp[i]推出一个区间可行解dp[left~right]=1;接下来从left+1推出下一个区间可行解,最后在加点判断即可。注意要在整个过程中维护一个变量k表示当前最大的满足dp[i]=1的i=k来保证算法是o(n)的。

#include <iostream>#include <cstdio>#include <cstring>using namespace std;#define mxn 50005#define LL long longint a[mxn];LL s[mxn];bool v[mxn];int w, n;bool check( int d ){    memset( v, 0, sizeof(v) ); v[0] = 1;    int k = 0;    for( int i = 1; i <= n; ++i ){        if(v[n]) return true;        if( v[i-1] == false ) continue;        for( int j = k + 1; j <= n; ++j ){            if( j==i ) continue;            LL sum = s[j] - s[i-1];            if( sum-1 > w ) break;            int tem ;            if((w-sum+j-i+1)%(j-i)!=0)                tem=1;            else tem=0;            tem+=(w-sum+j-i+1)/(j-i);            if( tem <= d ){                k = max( k, j );                v[j] = 1;            }        }    }    for( int i = n; i >= 0; --i ){        int sum = s[n] - s[i-1];        if( sum -1> w ) break;        if( v[i-1] ) return true;    }    if( v[n] ) return true;    return false;}int main(){    while( scanf( "%d%d", &w, &n ) == 2 && w ){        for( int i = 1; i <= n; ++i )            scanf( "%d", a + i ), ++a[i];        s[0] = 0;        for( int i = 1; i <= n; ++i )            s[i] = s[i-1] + a[i];        int l = 1, ans,r = w;        while( l <= r ){            int m = ( l + r ) >> 1;            if( check(m) ){                ans=m;                r = m-1;            }            else l = m + 1;        }        printf( "%d\n", ans );    }    return 0;}