现在的位置: 首页 > 综合 > 正文

UVALive 6190

2014年02月27日 ⁄ 综合 ⁄ 共 1006字 ⁄ 字号 评论关闭

这道题卡了我们整场,我们想到了二分答案+判断可行性,但是卡在判断可行性上了,首先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 long

int 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;
}

抱歉!评论已关闭.