zoukankan      html  css  js  c++  java
  • [题解] [JSOI2014] 拼图

    题面

    题解

    这个 (n * m leq 100000) 数据范围告诉我们要根号分治

    我们对于一段区间 ([u, d]) (上下的区间), 将所有拼图分为两类, 一类是这块中在这一段区间从左到右全都是 0 , 或者是只有一部分是 0

    那么最后这一段区间的答案就是把全是零的放在中间, 左边接一个 0 最多的, 右边接一个 0 最多的

    有可能这两个最多的是同一个, 所以还要记一个次大值

    • (n leq m)

    直接暴力枚举 (u) , (d) , 前缀和查询这一段是否全是 0

    复杂度 (O(n^2 * m))

    • (n > m)

    悬线法求出每个点最上面的 1 , 设为 (up[i][j])

    对于每一个 0 点, 拿 ([up[i][j] - 1, i]) 这一段区间去更新答案

    复杂度 (O(nm * m))

    感觉对这种根号分治的题目了解的还不是很多啊

    Code

    #include <algorithm>
    #include <iostream>
    #include <cstring>
    #include <cstdio>
    const int N = 100005; 
    using namespace std;
    
    int n, m, w[N], s, l[N], r[N], a[N], sum[N], ans, up[N], T; 
    
    template < typename T >
    inline T read()
    {
        T x = 0, w = 1; char c = getchar();
        while(c < '0' || c > '9') { if(c == '-') w = -1; c = getchar(); }
        while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
        return x * w; 
    }
    
    int id(int i, int j) { if(i < 1 || j < 1) return 0; return (j - 1) * n + i; }
    
    int S(int u, int l, int d, int r) { return sum[id(d, r)] - sum[id(d, l - 1)] - sum[id(u - 1, r)] + sum[id(u - 1, l - 1)]; }
    
    void calc(int u, int d)
    {
        for(int i = 1; i <= s; i++)
    	for(int j = l[i], len = 0; j <= r[i]; j++)
    	{
    	    S(u, j, d, j) ? len = 0 : len++; 
    	    ans = max(ans, (d - u + 1) * len); 
    	}
        int tmp = 0; pair<int, int> lmx, rmx, lsmx, rsmx; 
        for(int i = 1; i <= s; i++)
        {
    	int x = 0, y = 0; 
    	for(int j = l[i]; j <= r[i]; j++)
    	{
    	    if(!S(u, j, d, j)) x++;
    	    else break; 
    	}
    	for(int j = r[i]; j >= l[i]; j--)
    	{
    	    if(!S(u, j, d, j)) y++;
    	    else break; 
    	}
    	if(x == w[i]) tmp += w[i]; 
    	else
    	{
    	    if(x > lmx.second) lsmx = lmx, lmx.second = x, lmx.first = i;
    	    else if(x > lsmx.second) lsmx.second = x, lsmx.first = i;
    	    if(y > rmx.second) rsmx = rmx, rmx.second = y, rmx.first = i;
    	    else if(y > rsmx.second) rsmx.second = y, rsmx.first = i; 
    	}
        }
        if(lmx.first != rmx.first)
    	ans = max(ans, (d - u + 1) * (tmp + lmx.second + rmx.second));
        else
        {
    	ans = max(ans, (d - u + 1) * (tmp + lmx.second));
    	ans = max(ans, (d - u + 1) * (tmp + rmx.second)); 
    	ans = max(ans, (d - u + 1) * (tmp + lmx.second + rsmx.second));
    	ans = max(ans, (d - u + 1) * (tmp + rmx.second + lsmx.second)); 
        }
    }
    
    int main()
    {
        T = read <int> ();
        while(T--)
        {
    	s = read <int> (), n = read <int> (), ans = m = 0; 
    	for(int i = 1; i <= s; i++)
    	{
    	    w[i] = read <int> (), l[i] = m + 1, m += w[i], r[i] = m;
    	    for(int j = 1; j <= n; j++)
    		for(int k = l[i]; k <= r[i]; k++)
    		    scanf("%1d", &a[id(j, k)]); 
    	}
    	for(int i = 1; i <= n; i++)
    	    for(int j = 1; j <= m; j++)
    		sum[id(i, j)] = sum[id(i - 1, j)] + sum[id(i, j - 1)] - sum[id(i - 1, j - 1)] + a[id(i, j)];
    	for(int j = 1; j <= m; j++)
    	    for(int i = 1; i <= n; i++)
    	    {
    		if(a[id(i, j)]) up[id(i, j)] = i;
    		else up[id(i, j)] = up[id(i - 1, j)]; 
    	    }
    	if(n < m)
    	{
    	    for(int i = 1; i <= n; i++)
    		for(int j = i; j <= n; j++) calc(i, j);
    	}
    	else
    	{
    	    for(int i = 1; i <= n; i++)
    		for(int j = 1; j <= m; j++)
    		    if(!a[id(i, j)]) calc(up[id(i, j)] + 1, i);
    	}
    	printf("%d
    ", ans); 
        }
        return 0; 
    }
    
  • 相关阅读:
    Oracle Instant Client(即时客户端) 安装与配置
    面试中经典的数据库问题
    MySQL 大表优化方案
    mysql中Timestamp,Time,Datetime 区别
    HTML学习之给div高度设置百分比不生效的问题
    textarea文本域宽度和高度width及height自动适应实现代码
    JAVA基础----java中E,T,?的区别?
    去除ArrayList集合中的重复自定义对象元素
    sql select中加入常量列
    mysql 将null转代为0
  • 原文地址:https://www.cnblogs.com/ztlztl/p/12292713.html
Copyright © 2011-2022 走看看