BZOJ 4207 Can

分治+爆搜

仔细想想,如果给我一个很长的区间,问我这个区间是不是极好的,我好像都不太会。。。那就考虑乱搞吧

如果数据随机的话,一个直观的感觉是合法长度很短。

考虑爆搜,我们需要提高爆搜的速度,肯定是要让它较快找到最长的解。一个有效的方法是从中间向两边搜。一方面,不考虑枚举选哪一个数,单单就直观上看,枚举起点的搜法像n^2的,分治的搜法像nlogn的,所以后者应该会更快。另一方面,如果答案很长则分治从中间开始很容易找到最优解,然后最优性剪枝就可以飞起来。这样递归往两边分治,能够较快找到最长答案。相反,如果答案很短,那每一次爆搜的长度就很短。到底能不能卡我也不清楚,反正它能过

不小心又港记了

#include
#define N 100005
#define D 5
using namespace std;
namespace runzhe2000
{
    int read()
    {
        int r = 0; char c = getchar();
        for(; c < '0' || c > '9'; c = getchar());
        for(; c >='0' && c <='9'; r = r*10+c-'0', c = getchar());
        return r;
    }
    int n, d, k, a[N][D], ans, ansl, ansr, liml, limr, vis[N], len;
    bool invis(int *x)
    {
        for(int i = 1; i <= d; i++)
            if(vis[x[i]])return true; 
        return false;
    }
    void dfs(int l, int r, int f)
    {
        if(f > k) return;
        for(; invis(a[l-1]) && liml < l; l--);
        for(; invis(a[r+1]) && r < limr; r++);
        if(liml < l)
        {
            int *al = a[l-1];
            for(int i = 1; i <= d; i++)
            {
                vis[al[i]] = 1;
                dfs(l-1,r,f+1);
                vis[al[i]] = 0;
            }
        }
        if(r < limr)
        {
            int *ar = a[r+1];
            for(int i = 1; i <= d; i++)
            {
                vis[ar[i]] = 1;
                dfs(l,r+1,f+1);
                vis[ar[i]] = 0;
            }
        }
        (len = r-l+1) > ans || (len == ans && l < ansl) ? ans = len, ansl = l, ansr = r : 0;
    }
    void solve(int l, int r)
    {
        if(l > r || r-l+1 < ans) return;
        int mid = (l+r)>>1, *amid = a[mid];
        liml = l; limr = r;
        for(int i = 1; i <= d; i++)
        {
            vis[amid[i]] = 1;
            dfs(mid,mid,1);
            vis[amid[i]] = 0;
        }
        solve(l,mid-1); solve(mid+1,r);
    }
    void main()
    {
        int T = read();
        for(int TT = 1; TT <= T; TT++)
        {
            ans = 0;
            n = read(), d = read(), k = read();
            for(int i = 1; i <= n; i++)
                for(int j = 1; j <= d; j++)
                    a[i][j] = read();
            solve(1,n);
            printf("Case #%d: %d %d\n",TT,ansl - 1,ansr - 1);
        }
    }
}
int main()
{
    runzhe2000::main();
}

你可能感兴趣的:(其它-分治,其它-搜索)