牛客多校 Sudoku Subrectangles (好题)

问你1000*1000的字母矩阵中,有多少个行列中均无相同元素的.
用尺取预处理出每个元素向右走多少一路上没有重复,向下走一路上没有重复.
枚举左上端点,然后扫一遍第一行,然后用类似打标记的方法,找到接下来的每一行,最长可以延伸多少,然后在扫一遍每一行,看他到底能够延伸多长(min)

#include <iostream>
#include <vector>
#include <set>
#define debug(x) //std::cerr << #x << " = " << (x) << std::endl
using namespace std;
typedef long long LL;
const int MAXN = 1e3 + 17;
const int MOD = 998244353;
int mp[MAXN][MAXN];
int rg[MAXN][MAXN],down[MAXN][MAXN];
int main()
{
#ifdef noob
    freopen("Input.txt", "r", stdin);
    freopen("Output.txt", "w", stdout);
#endif
    LL n,m,ans = 0;
    cin>>n>>m;
    for (int i = 0; i < n; ++i)
    {
        string str;
        cin>>str;
        for (int j = 0; j < m; ++j)
        {
            if(str[j]>='a')
                mp[i][j] = str[j]-'a';
            else
                mp[i][j] = str[j]-'A'+26;
            rg[i][j] = m-j-1;
            down[i][j] = n-i-1;
        }
    }
    for (int i = 0; i < n; ++i)
    {
        int l = 0,r = 0;
        set<int > s;
        while(r<m)
        {
            if(s.find(mp[i][r])==s.end())
            {
                s.insert(mp[i][r]);
                r++;
            }
            else
            {
                rg[i][l] = r-l-1;
                s.erase(mp[i][l]);
                l++;
            }
        }

    }
    for (int j = 0; j < m; ++j)
    {
        int l = 0,r = 0;
        set<int > s;
        while(r<n)
        {
            if(s.find(mp[r][j])==s.end())
            {
                s.insert(mp[r][j]);
                r++;
            }
            else
            {
                down[l][j] = r-l-1;
                s.erase(mp[l][j]);
                l++;
            }
        }
    }
    for (int i = 0; i < n; ++i)
    {
        for (int j = 0; j < m; ++j)
        {
            vector<int > mx(60,0),flag(60,0);
            int sum = 0,mn = 100;
            for (int p = 0; p <= rg[i][j]; ++p)
            {
                int x = p+j;
                flag[min(mn,down[i][x])]++;
                mn = min(mn,down[i][x]);
                sum++;
            }
            for (int k = 0; sum&&k < 60; ++k)
            {
                mx[k] = sum;
                sum -= flag[k];
            }
            int mnx = 100;
            for (int p = 0; p < 60; ++p)
            {
                int x = p+i;
                if(x>=n) break;
                ans += min(mnx,min(rg[x][j]+1,mx[p]));
                mnx = min(mnx,min(rg[x][j]+1,mx[p]));
            }
        }
    }
    cout<<ans<<endl;
    return 0;
}

事实上只要有了52*52*nm的算法,就可以容易的想出这种新做法,但是我想了很久才想出来52*52的..这题很好,但是我真的不会,别人的题解叶看不懂,T^T

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值