bzoj 5103 [POI2018]Ró?norodno??

这个题没有想出来。。

首先显然的一点是我们要对每种颜色做一次不重复的贡献计算。

同种颜色的贡献就是矩形的并。从网上查了资料,矩形面积并用的是扫描线,那么这个我们也可以用扫描线了。

我们考虑枚举横坐标,维护存在于当前横坐标的所有纵坐标的区间。一个性质是所有的矩形都是边长为k的正方形,那么在加入或删除一个区间时只可能影响到一个连续的区间。我们只需要对这个区间操作就行了。

我用的set维护,因为bzoj开O2,所以比其他数据结构要快一些,但是没有bitset快,要跑47s,记得加上fread,这个题的读入量达到了9e6。

前段时间好迷啊,bzoj号莫名上不去,只能借同学得了,看别人题解看不懂,浪费时间去看代码。。后来发现是自己没脑子了。。

#include <bits/stdc++.h>
#define min(a,b) ((a)<(b)?(a):(b))
#define max(a,b) ((a)>(b)?(a):(b))
#define for1(a,b,i) for(int i=a;i<=b;++i)
#define FOR2(a,b,i) for(int i=a;i>=b;--i)
using namespace std;
typedef long long ll;
char xch,xB[1<<15],*xS=xB,*xTT=xB;
#define getc() (xS==xTT&&(xTT=(xS=xB)+fread(xB,1,1<<15,stdin),xS==xTT)?0:*xS++)
inline int read() {
    int x=0,f=1;
    char ch=getc();
    while(ch<‘0‘|ch>‘9‘){if(ch==‘-‘)f=-1;ch=getc();}
    while(ch>=‘0‘&&ch<=‘9‘){x=x*10+ch-‘0‘;ch=getc();}
    return x*f;
}

#define M 3005
#define N 100005
int n,m,K;
int a[M][M],size[N],sum[M][M];

struct node {
    int c;
    short x,y;
}buc[M*M];

struct point {
    short l,r;

    inline bool operator <(const point &a) const {
        return l<a.l;
    }
};

multiset <point> cc;
multiset <point>::iterator it,i;

inline void add_(int x,int l,int r,bool t) {
    if(x>n) return;
    if(!t) cc.insert((point){l,r});
    it=cc.lower_bound((point){l,r});
    int lx,rx;
    if(it==cc.begin()) lx=0;
    else i=it,i--,lx=(*i).r;
    i=it,i++;
    rx=i==cc.end()?m+1:(*i).l;
    ++lx,--rx;
    lx=max(lx,l),rx=min(rx,r);
    if(lx<=rx) {
        int k=t?-1:1;
        sum[x][lx]+=k;
        sum[x][rx+1]-=k;
    }
    if(t) cc.erase(it);
}

void solve_(int l,int r) {
    int h1=l-1,h2=l-1;
    while (h1<r&&h2<r) {
        int t0=buc[h1+1].x;
        int t1=buc[h2+1].x+K;
        if(t0<=t1) ++h1,add_(t0,buc[h1].y,buc[h1].y+K-1,0);
        if(t1<=t0) ++h2,add_(t1,buc[h2].y,buc[h2].y+K-1,1);
    }
    for1(h2+1,r,i) add_(buc[i].x+K,buc[i].y,buc[i].y+K-1,1);
    cc.clear();
}

int main () {
//    freopen("a.in","r",stdin);
    n=read(),m=read(),K=read();
    for1(1,n,i) for1(1,m,j) {
        a[i][j]=read();
        ++size[a[i][j]];
    }
    for1(1,100000,i) size[i]+=size[i-1];
    FOR2(n,1,i) FOR2(m,1,j) buc[size[a[i][j]]--]=(node){a[i][j],i,j};

    int l=1,r;
    while (l<=n*m) {
        r=l;
        while (buc[r+1].c==buc[l].c) ++r;
        solve_(l,r);
        l=r+1;
    }
    for1(1,n,i) {
        for1(1,m,j) sum[i][j]+=sum[i][j-1];
        for1(1,m,j) sum[i][j]+=sum[i-1][j];
    }
    ll tot=0;
    int ans=0;
    for1(K,n,i) for1(K,m,j) tot+=sum[i][j],ans=max(ans,sum[i][j]);
    printf("%d %lld\n",ans,tot);
}

原文地址:https://www.cnblogs.com/asd123www/p/9579670.html

时间: 2024-08-01 17:26:27

bzoj 5103 [POI2018]Ró?norodno??的相关文章

BZOJ 3280: 小R的烦恼 &amp; BZOJ 1221: [HNOI2001] 软件开发

3280: 小R的烦恼 Time Limit: 10 Sec  Memory Limit: 512 MBSubmit: 399  Solved: 200[Submit][Status][Discuss] Description 小R最近遇上了大麻烦,他的程序设计挂科了.于是他只好找程设老师求情.善良的程设老师答应不挂他,但是要求小R帮助他一起解决一个难题. 问题是这样的,程设老师最近要进行一项邪恶的实验来证明P=NP,这个实验一共持续n天,第i天需要a[i]个研究生来给他搬砖.研究生毕竟也是人,

bzoj 3280: 小R的烦恼(费用流)

3280: 小R的烦恼 Time Limit: 10 Sec  Memory Limit: 512 MB Submit: 300  Solved: 154 [Submit][Status][Discuss] Description 小R最近遇上了大麻烦,他的程序设计挂科了.于是他只好找程设老师求情.善良的程设老师答应不挂他,但是要求小R帮助他一起解决一个难题. 问题是这样的,程设老师最近要进行一项邪恶的实验来证明P=NP,这个实验一共持续n天,第i天需要a[i]个研究生来给他搬砖.研究生毕竟也是

[武汉加油] bzoj 5099: [POI2018]Pionek 几何+双指针

几何+双指针 题目大意:现在有 \(n\) 个向量,请你选出来一些向量使它们的和的长度最大,输出最大值的平方. 假如我们已经知道了最终向量的方向,我们要想使长度最大,就需要将所有投影在最终向量正方向上的向量都加起来. 所以我们可以按角度枚举最终向量的方向,我们需要加起来的就是一段移动的区间,我们可以用双指针来维护加起来的向量. 因为最终向量的方向有可能是给出的向量,也有可能是向量之间间隔的方向,所以每次移动指针的时候都要更新一下答案. 因为开始给出的向量不一定有序,所以我们需要先将向量排序. #

●BZOJ BZOJ 4408 [Fjoi 2016]神秘数

题链: http://www.lydsy.com/JudgeOnline/problem.php?id=4408 题解: 主席树 首先,对于一些数来说, 如果可以我们可以使得其中的某些数能够拼出 1-ret 那么此时的ANS(神秘数)= ret+1 然后考虑,如果此时存在另一个数小于等于 ANS,(设该数为 x) 则一定可以在原来的1-ret的基础上拼出 1-ret+x 即 ANS 可以更新为 ret+x+1 所以具体的操作就是: 每次查询区间内小于ANS的数的和(SUM),然后如果SUM大于A

【BZOJ】【3280】小R的烦恼

网络流/费用流 和软件开发那题基本相同,只是多加了一个“雇佣研究生”的限制:不同价格的研究生有不同的数量…… 那么只需加一个附加源点,对每一种研究生连边 S->ss 容量为l[i],费用为p[i]:再改由附加源点向每天的流入点(i+n)连边即可. 1 /************************************************************** 2 Problem: 3280 3 User: Tunix 4 Language: C++ 5 Result: Acce

BZOJ 4725: [POI2017]Reprezentacje r&#243;?nicowe

Description 一个数列. \(a_1=1,a_2=2\) 当 \(n>2\) 时 \(a_n\left\{\begin{matrix}2a_{n-1},\text{n is an odd number}\\a_{n-1}+r_{n-1},\text{ n is an even number } \end{matrix}\right.\) \(S_n=\{a_i-a_j,1 \leqslant j<i\leqslant n\}\) \(r_n\) 为最小不在 \(S_n\) 中的非负整

洛谷 P2709 BZOJ 3781 小B的询问

题目描述 小B有一个序列,包含N个1~K之间的整数.他一共有M个询问,每个询问给定一个区间[L..R],求Sigma(c(i)^2)的值,其中i的值从1到K,其中c(i)表示数字i在[L..R]中的重复次数.小B请你帮助他回答询问. 输入输出格式 输入格式: 第一行,三个整数N.M.K. 第二行,N个整数,表示小B的序列. 接下来的M行,每行两个整数L.R. 输出格式: M行,每行一个整数,其中第i行的整数表示第i个询问的答案. 输入输出样例 输入样例#1: 6 4 3 1 3 2 1 1 3

BZOJ 1012: [JSOI2008]最大数maxnumber(线段树)

012: [JSOI2008]最大数maxnumber Time Limit: 3 Sec  Memory Limit: 162 MB Description 现在请求你维护一个数列,要求提供以下两种操作:1. 查询操作.语法:Q L 功能:查询当前数列中末尾L个数中的最大的数,并输出这个数的值.限制:L不超过当前数列的长度.2. 插入操作.语法:A n 功能:将n加上t,其中t是最近一次查询操作的答案(如果还未执行过查询操作,则t=0),并将所得结果对一个固定的常数D取模,将所得答案插入到数列

【BZOJ】【1016】【JSOI2008】最小生成树计数

Kruskal/并查集+枚举 唉我还是too naive,orz Hzwer 一开始我是想:最小生成树删掉一条边,再加上一条边仍是最小生成树,那么这两条边权值必须相等,但我也可以去掉两条权值为1和3的,再加上权值为2和2的,不也满足题意吗?事实上,如果这样的话……最小生成树应该是1和2,而不是1和3或2和2!!! 所以呢?所以对于一个图来说,最小生成树有几条边权为多少的边,都是固定的!所以我们可以做一遍Kruskal找出这些边权,以及每种边权出现的次数.然后,对于每种边权,比方说出现了$v_i$