T1

Description

给出n个矩形的顶点坐标(每个矩形的底边都在x轴上),求这n个矩形所组成图形的轮廓线的顶点。

Input

第一行一个整数n,表示矩形个数。

以下n行,每行3个整数,分别表示矩形的x坐标区间及矩形的高度h[i]。

Output

第一行一个整数m,表示轮廓线顶点个数。

以下m行,每行一个坐标表示轮廓线上的顶点。从左到右遍历轮廓线并顺序输出顶点。第一个和最后一个节点的y坐标必然为0。

Sample Input

2

3 0 2

4 1 3

Sample Output

6

0 0

0 3

1 3

1 4

3 4

3 0

HINT

1<=n<=100000,1<=h[i]<=109,-109<=l[i]<r[i]<=109

Solution

这道题是离散+线段树的裸题了。用扫描线+堆也是可以做的。(由于本弱太弱,所以线段树不小心写炸了QAQ)

 #include<cmath>
#include<ctime>
#include<queue>
#include<stack>
#include<cstdio>
#include<vector>
#include<cstring>
#include<iostream>
#include<algorithm>
#define N 100001
#define M 1000001
using namespace std;
struct building{
int l,r,h;
}a[N];
struct linetree{
int l,r,h;
}lt[M];
struct answer{
int x,y;
}ans[N<<];
int p[N<<],n,cnt,tot;
inline void build(int i,int l,int r){
lt[i].l=l;lt[i].r=r;
if(l+<r){
int lef=i<<,rig;rig=lef|;
int mid=(l+r)>>;
build(lef,l,mid);
build(rig,mid,r);
}
}
inline void cover(int i,int l,int r,int h){
if(p[lt[i].l]>=l&&p[lt[i].r]<=r)
lt[i].h=max(lt[i].h,h);
else if(lt[i].l+<lt[i].r){
int lef=i<<,rig;rig=lef|;
int mid=(lt[i].l+lt[i].r)>>;
lt[lef].h=max(lt[lef].h,lt[i].h);
lt[rig].h=max(lt[rig].h,lt[i].h);
if(r>p[mid]) cover(rig,l,r,h);
if(l<p[mid]) cover(lef,l,r,h);
}
}
inline void ask(int i){
if(lt[i].l+<lt[i].r){
int lef=i<<,rig;rig=lef|;
lt[lef].h=max(lt[lef].h,lt[i].h);
lt[rig].h=max(lt[rig].h,lt[i].h);
ask(lef);ask(rig);
}
else{
ans[++cnt].x=p[lt[i].l];
ans[cnt].y=lt[i].h;
}
}
inline void init(){
scanf("%d",&n);
for(int i=;i<=n;i++){
scanf("%d%d%d",&a[i].h,&a[i].l,&a[i].r);
p[++cnt]=a[i].l;p[++cnt]=a[i].r;
}
sort(p+,p++cnt);tot=;
for(int i=;i<=cnt;i++)
if(p[i]!=p[i-])
p[++tot]=p[i];
cnt=;
build(,,tot);
for(int i=;i<=n;i++)
cover(,a[i].l,a[i].r,a[i].h);
cnt=;ask();
ans[++cnt].x=p[tot];
tot=;
for(int i=;i<=cnt;i++)
if(ans[i].y!=ans[i-].y)
tot+=;
printf("%d\n",tot);
for(int i=;i<=cnt;i++)
if(ans[i].y!=ans[i-].y){
printf("%d %d\n",ans[i].x,ans[i-].y);
printf("%d %d\n",ans[i].x,ans[i].y);
}
}
int main(){
freopen("build.in","r",stdin);
freopen("build.out","w",stdout);
init();
fclose(stdin);
fclose(stdout);
return ;
}

build

T2

Description

分别给你n个单词(n<=103)作为单词表和一篇包含m个单词(m<=105)的文章。

在文章中求出一段连续的区间使得区间所包含的单词表中的单词数最多(同个单词出现多次算一个)且区间内单词数最少。

Input

第一行一个数n,表示单词表单词数。

接下来n行,每行是一个长度不超过10的字符串,表示一个单词表中的单词。

接着是一个数m,表示文章中的单词数。

然后是m行长度不超过10的字符串,每个表示文章中的一个单词。

Output

输出文件共2行。

第1行为文章中最多包含的单词表单词数。

第2行表示在文章中包含最多单词表中的单词的最短的连续段的长度。

Sample Input

3

hot

dog

milk

5

hot

dog

dog

milk

hot

Sample Output

3

3

Solution

这道题其实是由2个子问题组成:求区间所包含的单词表中的单词数(以下简称所含单词数)最大值ans和满足最大值的最短区间长度。
前者只需要扫一遍文章,哈希判断是否在单词表中即可。
后者由于数据范围不支持O(n2)的算法,所以需运用到双指针扫描:
1. 将头尾指针指向第一个元素;
2. 向右移动尾指针,直到指到最后一个元素或区间内所含单词数=ans;
3. 向右移动头指针,直到区间为空或再向右移一个会导致区间内所含单词数≠ans,最短区间长度len=min(len,当前区间长度);
4.如果尾指针没有指向最后一个元素,将头尾指针均向右移一个,返回步骤2;否则结束。

(综上所述就是一道傻逼题,然后但是好像是因为一个特别傻逼的错然后爆零???)

 #include<cmath>
#include<ctime>
#include<queue>
#include<stack>
#include<cstdio>
#include<vector>
#include<cstring>
#include<iostream>
#include<algorithm>
#define L 12
#define Y 131
#define N 1001
#define M 100001
#define K 100003
using namespace std;
int h,t,sum;
int fir[K],nxt[K],cnt;
int u[N],to[M],la[N],lb[M],m,n,ans,tot;
char key[K][L],a[N][L],b[M][L];
inline int hash(char a[],int l){
int ret=;
for(int i=;i<=l;i++)
ret=(ret*Y*Y%K+a[i]*Y)%K;
return ret;
}
inline void init(){
scanf("%d",&n);
for(int i=;i<=n;i++){
scanf("%s",a[i]+);
la[i]=strlen(a[i]+);
}
scanf("%d",&m);
for(int i=;i<=m;i++){
scanf("%s",b[i]+);
lb[i]=strlen(b[i]+);
}
for(int i=,j,k;i<=n;i++){
k=hash(a[i],la[i]);
for(j=fir[k];j;j=nxt[j])
if(!strcmp(key[j]+,a[i]+))
break;
if(!j){
nxt[++cnt]=fir[k];fir[k]=cnt;
for(j=;j<=la[i];j++)
key[cnt][j]=a[i][j];
}
}
for(int i=,j,k;i<=m;i++){
k=hash(b[i],lb[i]);
for(j=fir[k];j;j=nxt[j])
if(!strcmp(key[j]+,b[i]+))
break;
if(j&&!u[j]) tot++;
u[j]++;to[i]=j;
}
memset(u,,sizeof(u));
ans=m;h=;
for(t=;t<=m;t++){
if(to[t]&&!u[to[t]]) ++sum;
++u[to[t]];
while(sum==tot){
ans=min(t-h+,ans);
u[to[h]]--;
if(!u[to[h]]) sum--;
++h;
}
}
if(!tot) ans=;
printf("%d\n%d\n",tot,ans);
}
int main(){
freopen("word.in","r",stdin);
freopen("word.out","w",stdout);
init();
fclose(stdin);
fclose(stdout);
return ;
}

word

T3

Description

给定一个N行M列(N,M<=1000)的非负整数矩阵,求一个最大的正方形子矩阵,该矩阵满足:
矩阵中每一个元素权值都大于0;
在满足上述条件的前提下,矩阵面积最大;
在满足上述条件的前提下,选择元素和最小的。

Input

第一行两个整数N,M。

接下来N行,每行M个整数。
Output

2个数,用空格隔开,第一个数为满足条件的矩阵的面积,第二个数为该矩阵各元素之和。
Sample Input

3 7

1 1 1 0 2 1 1

1 1 1 0 1 1 1

1 1 1 0 1 1 1
Sample Output

9 9

Solution

这道题可以分解成2个子问题:求满足条件的矩阵的最大边长len、满足最大边长的最小元素和sum,记输入的矩阵为a[][]。

前者可以通过枚举正方形的左边所在列j,然后求出以当前行i的最大长度为长,向上/下最多可以扩展到哪(即求第一个长度小于当前行的,单调队列即可),边长=min(长,宽)。

===============================================以下为具体步骤,不喜请跳过===============================================

前者可以先枚举正方形的左边所在列j,然后对于每一行i,求出从a[i][j]开始,向右连续的最右边的元素为a[i][k],记为rig[i][j]。

然后分别求出从a[i][j]开始,以rig[i][j]-j+1为长,向上和向下最多能扩展到哪,记为top[i][j]、down[i][j],

此时能形成的正方形边长为min(rig[i][j]-j+1,top[i][j]-down[i][j]+1),将这些值取最大值就是答案len了。

其中,rig[][]能通过O(n2)预处理处理出来,top[][]、down[][]可以分别用两个单调递增的单调队列求出来

(也就是求向上、向下第一个使得r[i][k]<r[i][j]的k,top[i][j]=k+1,down[i][j]=k-1),时间复杂度O(n2),枚举i,j也是O(n2)。

后者可以通过用类似上述方法判断当前i,j是否满足以(i,j)为左上角顶点的满足条件的正方形边长是否等于len。如果满足条件,计算出这个正方形的和s,则sum=min(sum,s)。

这个不必每次枚举计算,可以通过二维前缀和O(n2)预处理,O(1)求出。s=s[i+len-1][j+len-1]-s[i-1][j+len-1]-s[i+len-1][j-1]+s[i-1][j-1]。

(其实这天的题我口头AK了,只是都写炸了【我真是太弱了】)

 #include<cmath>
#include<ctime>
#include<queue>
#include<stack>
#include<cstdio>
#include<vector>
#include<cstring>
#include<iostream>
#include<algorithm>
#define N 1005
using namespace std;
typedef long long ll;
int r[N][N],l[N][N],q[N],n,m,h,t,ans;
ll a[N][N],s[N][N],sum=1e15;
inline int read(){
int ret=;char c=getchar();
while(!isdigit(c))
c=getchar();
while(isdigit(c)){
ret=ret*+c-'';
c=getchar();
}
return ret;
}
inline ll read_ll(){
ll ret=;char c=getchar();
while(!isdigit(c))
c=getchar();
while(isdigit(c)){
ret=ret*+c-'';
c=getchar();
}
return ret;
}
inline void init(){
n=read();m=read();
for(int i=;i<=n;i++)
for(int j=;j<=m;j++)
a[i][j]=read_ll();
for(int i=;i<=n;i++)
for(int j=;j<=m;j++)
s[i][j]=s[i][j-]+a[i][j];
for(int j=;j<=m;j++)
for(int i=;i<=n;i++)
s[i][j]+=s[i-][j];
for(int i=,k;i<=n;i++){
for(int j=;j<=m;j=k){
for(k=j;k<=m&&a[i][k];k++);
for(int l=j;l<k;l++)
r[i][l]=k;
while(k<=m&&!a[i][k]) ++k;
}
}
for(int j=;j<=m;j++){
h=;t=;
for(int i=;i<=n;i++){
while(h<=t&&r[i][j]<=r[q[t]][j]) t--;
l[i][j]=i-q[t];q[++t]=i;
}
}
q[]=n+;
for(int j=;j<=m;j++){
h=;t=;
for(int i=n;i;i--){
while(h<=t&&r[i][j]<=r[q[t]][j]) t--;
l[i][j]+=q[t]-i-;q[++t]=i;
ans=max(ans,min(l[i][j],r[i][j]-j));
}
}
for(int j=,k;j<=m;j++){
for(int i=;i<=n;i=k){
for(k=i;k<=n&&r[k][j]-j>=ans;k++);
if(k-i>=ans){
for(int l=k-ans;l>=i;l--)
sum=min(sum,s[l+ans-][j+ans-]-s[l-][j+ans-]-s[l+ans-][j-]+s[l-][j-]);
}
while(k<=n&&r[k][j]-j<ans) ++k;
}
}
printf("%d %lld\n",ans*ans,sum);
}
int main(){
freopen("matrix.in","r",stdin);
freopen("matrix.out","w",stdout);
init();
fclose(stdin);
fclose(stdout);
return ;
}

matrix

[日常训练]FJ省夏令营day1的更多相关文章

  1. 「日常训练」ZgukistringZ(Codeforces Round #307 Div. 2 B)

    题意与分析(CodeForces 551B) 这他妈哪里是日常训练,这是日常弟中弟. 题意是这样的,给出一个字符串A,再给出两个字符串B,C,求A中任意量字符交换后(不限制次数)能够得到的使B,C作为 ...

  2. 「日常训练」 Fire!(UVA-11624)

    与其说是训练不如说是重温.重新写了Java版本的代码. import java.util.*; import java.math.*; import java.io.BufferedInputStre ...

  3. 「日常训练」COMMON 约数研究(HYSBZ-1968)

    题意与分析 感谢https://www.cnblogs.com/Leohh/p/7512960.html的题解.这题话说原来不在我的训练范围,正好有个同学问我,我就拿来做做.数学果然不是我擅长的啊,这 ...

  4. 「日常训练」 Mike and Fun (CFR305D2B)

    题意(CodeForces 548B) 每次对01矩阵中的一位取反,问每次操作后,单列中最长连续1的长度. 分析 非常非常简单,但是我当时训练的时候WA了四次...无力吐槽了,人间 不值得.jpg 代 ...

  5. 「日常训练」Common Subexpression Elimination(UVa-12219)

    今天做的题目就是抱佛脚2333 懂的都懂. 这条题目干了好几天,最后还是参考别人的代码敲出来了,但是自己独立思考了两天多,还是有收获的. 思路分析 做这条题我是先按照之前的那条题目(The SetSt ...

  6. 集训队日常训练20181117 DIV2

    大佬们一顿操作猛如虎,拼命AC强啊 4262: 区间异或  Time Limit(Common/Java):1000MS/3000MS     Memory Limit:65536KByteTotal ...

  7. [日常训练]string

    Description 给定一个长度为$n$的字符串,串中的字符保证是前$k$个小写字母.你可以在字符串后再添加$m$个字符,使得新字符串所包含的不同的子序列数量尽量多.当然,前提是只能添加前$k$个 ...

  8. [日常训练]yayamao的神题

    Description $yayamao$是数学神犇,一天他在纸上计算起了$1/P$, 我们知道按照模拟除法可以得到准确解,例如$1/7=0.(142857),1/10=0.1(0)$.$yayama ...

  9. [日常训练]mod

    Description 给定$p_1,p_2,-,p_n,b_1,b_2,...,b_m$, 求满足$x\;mod\;p_1\;\equiv\;a_1,x\;mod\;p_2\;\equiv\;a_2 ...

随机推荐

  1. mysql--测试前缀索引能否用于order by 或者 group by

    创建一个测试用表 mysql> desc two; +-------+-------------+------+-----+---------+----------------+ | Field ...

  2. PAT 1030. 完美数列(25)

    给定一个正整数数列,和正整数p,设这个数列中的最大值是M,最小值是m,如果M <= m * p,则称这个数列是完美数列. 现在给定参数p和一些正整数,请你从中选择尽可能多的数构成一个完美数列. ...

  3. Conherence Function

    来源: 部分来自wiki:https://en.wikipedia.org/wiki/Coherence_(signal_processing): 部分来自网络其它内容. The coherence  ...

  4. Linux 网络编程详解十二

    UDP的特点 --无连接 --基于消息的数据传输服务 --不可靠 --UDP更加高效 UDP注意点 --UDP报文可能会丢失,重复 --UDP报文可能会乱序 --UDP缺乏流量控制(UDP缓冲区写满之 ...

  5. SpringMVC源码分析系列

    说到java的mvc框架,struts2和springmvc想必大家都知道,struts2的设计基本上完全脱离了Servlet容器,而springmvc是依托着Servlet容器元素来设计的,同时sp ...

  6. 【语言基础】c++ 备忘录

    1. C++ 整数类型范围 可以参照头文件limits.h定义的宏 #define INT_MAX       2147483647(32bit, 最大10位十进制) #define UINT_MAX ...

  7. STM32 (战舰)

    一.战舰STM32 1.引脚描述表---有ft 兼容5V 2.原理图----有ADC,不兼容5V 3.(1)学会基本外设:GPIO输入输出,外部中断,定时器,串口. (2)学会外设接口:SPI IIC ...

  8. coursera 公开课 文本挖掘和分析(text mining and analytics) week 1 笔记

    一.课程简介: text mining and analytics 是一门在coursera上的公开课,由美国伊利诺伊大学香槟分校(UIUC)计算机系教授 chengxiang zhai 讲授,公开课 ...

  9. Oracle在中文环境下出现乱码解决办法

       zysong.ttf下载是一款oracle字体乱码解决工具,实质于缺乏中文字体包! 01情况的例子 02情况的例子 01.在开始安装的时候出现乱码 下载zysong.ttf,unzip 解压 一 ...

  10. MAC OS上Nginx安装

    admin@admindeMac:local]$ brew install nginx ==> Installing dependencies for nginx: pcre, openssl ...