[APIO2009]
来自FallDream的博客,不经允许,请勿转载,谢谢。
------------------------------------------------------
1.Oil
给定一个n*m的矩阵,你要从中选出恰好3个k*k的不想交的矩阵,并使得矩阵数字的和最大。n,m<=1500
题解:很显然,三个矩阵只有两种排布方案:1)先横着或者竖着割成两段,然后在其中一边再分成两段。3)横着或者竖着分成三段。
所以我们用A[i][j]表示前i行j列选一个的最大值,其他三个角同理,然后处理一下横着和竖着的一个区间的最大值就可以啦。
#include<iostream>
#include<cstdio>
#define MN 1505
using namespace std;
inline int read()
{
int x = , f = ; char ch = getchar();
while(ch < '' || ch > ''){ if(ch == '-') f = -; ch = getchar();}
while(ch >= '' && ch <= ''){x = x * + ch - '';ch = getchar();}
return x * f;
} int n,m,k,ans=;
int f[][MN][MN];
int g[MN][MN],h[MN],e[MN][MN],d[MN][MN],c[MN];
int s[MN][MN]; inline int calc(int x,int y){return (x<=n&&y<=m&&x>=k&&y>=k)?(s[x][y]-s[x-k][y]-s[x][y-k]+s[x-k][y-k]):;} int main()
{
//freopen("test0.in","r",stdin);
n=read();m=read();k=read();
for(int i=;i<=n;i++)
for(int j=;j<=m;j++)
scanf("%d",&s[i][j]);
for(int i=;i<=n;i++)
for(int j=;j<=m;j++)
s[i][j]=s[i][j]+s[i-][j]+s[i][j-]-s[i-][j-];
for(int i=k;i<=n;i++)
for(int j=k;j<=m;j++)
g[i][j]=calc(i,j),h[i]=max(h[i],g[i][j]),c[j]=max(c[j],g[i][j]);
for(int i=k;i<=n;i++)
for(int j=k;j<=m;j++)
f[][i][j]=max(f[][i][j-],max(f[][i-][j],g[i][j]));
for(int i=k;i<=n;i++)
for(int j=m-k+;j;j--)
f[][i][j]=max(f[][i][j+],max(f[][i-][j],g[i][j+k-]));
for(int i=n-k+;i;i--)
for(int j=k;j<=m;j++)
f[][i][j]=max(f[][i][j-],max(f[][i+][j],g[i+k-][j]));
for(int i=n-k+;i;i--)
for(int j=m-k+;j;j--)
f[][i][j]=max(f[][i][j+],max(f[][i+][j],g[i+k-][j+k-])); for(int i=k;i<=n;i++)
{
int mx=;
for(int j=i;j<=n;j++)
mx=max(mx,h[j]),e[i][j]=mx;
}
for(int i=k;i<=m;i++)
{
int mx=;
for(int j=i;j<=m;j++)
mx=max(mx,c[j]),d[i][j]=mx;
}
for(int i=;i<=n;i++)
for(int j=;j<=m;j++)
{
if(i+k<=n&&i>=k&&j>=k&&j+k<=m)ans=max(ans,f[][i][j]+f[][i][j+]+e[i+k][n]);
if(i+k-<=n&&i>k&&j>k&&j+k-<=m) ans=max(ans,f[][i][j-]+f[][i][j]+e[k][i-]);
if(i+k<=n&&i>=k&&j>=k&&j+k<=m) ans=max(ans,f[][i][j]+f[][i+][j]+d[j+k][m]);
if(i+k<=n&&i>=k&&j>k&&j+k-<=m)ans=max(ans,f[][i][j]+f[][i+][j]+d[k][j-]);
}
for(int i=k+;i<=n;i++)
for(int j=i+k-;j+k<=n;j++)
ans=max(ans,e[k][i-]+e[i+k-][j]+e[j+k][n]);
for(int i=k+;i<=m;i++)
for(int j=i+k-;j+k<=m;j++)
ans=max(ans,d[k][i-]+d[i+k-][j]+d[j+k][m]);
cout<<ans;
return ;
}
B.会议中心
活动安排问题,但是要求选的活动最多的情况下字典序最小。 n<=200000
题解:
按照字典序从小到大,当一个线段[l,r]插入时,找到它的前驱后继[ll,rr]。只有当[ll,l)的方案数+(r,rr]的方案数+1恰好等于[ll,rr]的方案数的时候,它才能成为最优解,那么就把它选入答案。
怎样快速算出一个区间答案呢?倍增。我们离散后,用f[i][k]表示第i个点向后走2^k个区间最少到达哪里,预处理好后每次查询只要log.
复杂度nlogn
如果用set,代码就很短啦,但是我不想用set,练习一下平衡树吧。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define INF 2000000000
#define MN 200000
#define ML 18
using namespace std;
inline int read()
{
int x = , f = ; char ch = getchar();
while(ch < '' || ch > ''){ if(ch == '-') f = -; ch = getchar();}
while(ch >= '' && ch <= ''){x = x * + ch - '';ch = getchar();}
return x * f;
} int fa[MN*+],c[MN*+][],size[MN*+],nn[MN*+],q[MN*+],top,sign=,rt=,cc=;
int f[MN*+][ML+];
int n,l[MN+],r[MN+],l2[MN*+],tot=,cnt=;
struct cus{int l,r,num;}s[MN+];
bool cmp(cus x,cus y){return x.r<y.r||(x.r==y.r&&x.l>y.l);} void ins(int&x,int k,int last)
{
if(!x){x=++cc;fa[x]=last;nn[x]=k;size[x]=;return;}
if(k<=nn[x]) ins(c[x][],k,x);
else ins(c[x][],k,x);
size[x]=size[c[x][]]+size[c[x][]]+;
if(max(size[c[x][]],size[c[x][]])>0.7*size[x]) sign=x;
} void dfs(int x)
{
if(c[x][]) dfs(c[x][]);
q[++top]=x;
if(c[x][]) dfs(c[x][]);
fa[x]=c[x][]=c[x][]=;
} void build(int x,int l,int r,int last)
{
if(l>r){x=;return;}int mid=l+r>>;
x=q[mid];fa[x]=last;
build(c[x][],l,mid-,x);
build(c[x][],mid+,r,x);
size[x]=size[c[x][]]+size[c[x][]]+;
} void rebuild()
{
int y=fa[sign];top=;dfs(sign);
if(!y) build(rt,,top,);
else build(c[y][c[y][]==sign],,top,y);
sign=;
} int query(int x,int rk)
{
if(!x) return ;
if(nn[x]<=rk) return size[c[x][]]++query(c[x][],rk);
else return query(c[x][],rk);
} int ask_before(int x,int rk)
{
if(!x) return ;int q;
if(nn[x]<rk) return (q=ask_before(c[x][],rk))?q:nn[x];
else return ask_before(c[x][],rk);
} int ask_after(int x,int rk)
{
if(!x) return ;int q;
if(nn[x]>rk) return (q=ask_after(c[x][],rk))?q:nn[x];
else return ask_after(c[x][],rk);
} int calc(int l,int r)
{
int sum=;
for(int i=ML;i>=;i--)
if(f[l][i]<=r+)
l=f[l][i],sum+=<<i;
// cout<<"calc"<<l<<" "<<r<<" "<<sum<<endl;
return sum;
} inline bool check(int l,int r)
{
int x=query(rt,l-),y=query(rt,r);
// cout<<"check"<<l<<" "<<r<<" "<<x<<" "<<y<<endl;
return query(rt,l-)==query(rt,r)&&(y&);
} int main()
{
n=read();
for(int i=;i<=n;i++)
s[i].l=l[i]=read(),s[i].r=r[i]=read(),s[i].num=i;
for(int i=;i<=n;i++)
l2[++tot]=s[i].l,l2[++tot]=s[i].r;
sort(l2+,l2+tot+);
for(int i=;i<=tot;i++)
if(l2[i]!=l2[i-])
l2[++cnt]=l2[i];
memset(f,,sizeof(f));;
for(int i=;i<=n;i++)
{
l[i]=lower_bound(l2,l2+cnt+,l[i])-l2;
r[i]=lower_bound(l2,l2+cnt+,r[i])-l2;
f[l[i]][]=min(f[l[i]][],r[i]+);
}
for(int i=cnt;i>=;i--)
{
f[i][]=min(f[i][],f[i+][]);
for(int k=;k<=ML;k++)
if(f[i][k-]<INF)
f[i][k]=f[f[i][k-]][k-];
// for(int k=0;k<=4;k++)
// cout<<i<<" "<<k<<" "<<f[i][k]<<endl;
}
ins(rt,,);ins(rt,INF,);
printf("%d\n",calc(,INF));bool yes=false;
for(int i=;i<=n;i++)
{
if(!check(l[i],r[i])) continue;
int ll=ask_before(rt,l[i]),rr=ask_after(rt,r[i]);
if(calc(ll,l[i]-)+calc(r[i]+,rr)+!=calc(ll,rr)) continue;
ins(rt,l[i],);ins(rt,r[i],);
if(yes)printf(" ");else yes=true;
printf("%d",i);
}
return ;
}
C.Atm
这道题是我以前做的.....
http://www.cnblogs.com/FallDream/p/bzoj1179.html
[APIO2009]的更多相关文章
- 【Tarjan】+【SPFA】APIO2009 Atm
一.算法介绍 tarjan——求解有向图强连通分量.这个算法在本人的一篇blog中有介绍,这里就不赘述了.贴上介绍tarjan的的blog链接:http://www.cnblogs.com/Maki- ...
- [BZOJ1177][Apio2009]Oil
[BZOJ1177][Apio2009]Oil 试题描述 采油区域 Siruseri政府决定将石油资源丰富的Navalur省的土地拍卖给私人承包商以建立油井.被拍卖的整块土地为一个矩形区域,被划分为M ...
- 【BZOJ】【1177】【APIO2009】Oil
DP 找出三个正方形,可以转化为将整个油田切成三个矩形块,每块中各找一个正方形区域,切的形式只有6种,分类更新ans即可 题解:http://trinklee.blog.163.com/blog/st ...
- 枚举(分类讨论):BZOJ 1177: [Apio2009]Oil
1177: [Apio2009]Oil Time Limit: 15 Sec Memory Limit: 162 MBSubmit: 1477 Solved: 589[Submit] Descri ...
- BZOJ 1179: [Apio2009]Atm( tarjan + 最短路 )
对于一个强连通分量, 一定是整个走或者不走, 所以tarjan缩点然后跑dijkstra. ------------------------------------------------------ ...
- 1179: [Apio2009]Atm
1179: [Apio2009]Atm Time Limit: 15 Sec Memory Limit: 162 MBSubmit: 1629 Solved: 615[Submit][Status ...
- [APIO2009]会议中心
[APIO2009]会议中心 题目大意: 原网址与样例戳我! 给定n个区间,询问以下问题: 1.最多能够选择多少个不相交的区间? 2.在第一问的基础上,输出字典序最小的方案. 数据范围:\(n \le ...
- BZOJ_1179_[Apio2009]Atm_tarjan+spfa
BZOJ_1179_[Apio2009]Atm_tarjan+spfa 题意:http://www.lydsy.com/JudgeOnline/problem.php?id=1179 分析: 显然有环 ...
- P3627 [APIO2009]抢掠计划
P3627 [APIO2009]抢掠计划 Tarjan缩点+最短(最长)路 显然的缩点...... 在缩点时,顺便维护每个强连通分量的总权值 缩完点按照惯例建个新图 然后跑一遍spfa最长路,枚举每个 ...
- 【BZOJ】【1178】【APIO2009】convention会议中心
贪心 如果不考虑字典序的话,直接按右端点排序,能选就选,就可以算出ans…… 但是要算一个字典序最小的解就比较蛋疼了= = Orz了zyf的题解 就是按字典序从小到大依次枚举,在不改变答案的情况下,能 ...
随机推荐
- nyoj 公约数和公倍数
公约数和公倍数 时间限制:1000 ms | 内存限制:65535 KB 难度:1 描述 小明被一个问题给难住了,现在需要你帮帮忙.问题是:给出两个正整数,求出它们的最大公约数和最小公倍数. ...
- R语言基础2
----------------------------------R语言学习与科研应用,科研作图,数据统计挖掘分析,群:719954246-------------------------- 通常, ...
- React 深入系列1:React 中的元素、组件、实例和节点
文:徐超,<React进阶之路>作者 授权发布,转载请注明作者及出处 React 深入系列,深入讲解了React中的重点概念.特性和模式等,旨在帮助大家加深对React的理解,以及在项目中 ...
- kali rolling更新源之gpg和dirmngr问题
1.编辑 /etc/apt/source.list gedit /etc/apt/sources.list 输入更新源,可以选任何可用更新源,这里设置官方源 deb http://http.kali. ...
- vue jsx 使用指南
vue jsx 使用指南 vue jsx 语法与 react jsx 还是有些不一样,在这里记录下. let component = null // if 语句 if (true) { compone ...
- Python内置函数(9)——int
英文文档: class int(x=0) class int(x, base=10) Return an integer object constructed from a number or str ...
- apigw鉴权分析(1-5)亚马逊 - 鉴权分析
一.访问入口 https://developer.amazon.com/public/zh 二.鉴权方式分析 三.分解结论
- 京东2019春招Java工程师编程题题解
生成回文串 题目描述 对于一个字符串,从前开始读和从后开始读是一样的,我们就称这个字符串是回文串. 例如"ABCBA","AA","A"是回 ...
- python tornado TCPserver异步协程实例
项目所用知识点 tornado socket tcpserver 协程 异步 tornado tcpserver源码抛析 在tornado的tcpserver文件中,实现了TCPServer这个类,他 ...
- mysql 练习题
导出现有数据库数据: C:\Users\Administrator>mysqldump -u root db1>D:\agon\db1.sql -p #结构+数据 mysqldump - ...