[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的题解 就是按字典序从小到大依次枚举,在不改变答案的情况下,能 ...
随机推荐
- string类的简洁版实现
说是原创,差不多算是转载了,我也是看了好多大牛的写法,大牛的建议,自己加一总结,形成代码: 实现一个简洁版的string类,我觉得,下面的也够了:另外需要参见另外的写法: http://blog.cs ...
- java从网络中下载图片到本地
public class imageDownload { public static void main(String[] args) { String url = "http://loca ...
- es6+react.js组件入门初探
React是一个用于构建用户见面的javascript库. React主要用于构建UI,许多人认为React是MVC中的V(视图) React起源于Facebook的内部项目,用来架设Instagra ...
- Python 列表嵌套多种实现方式
#coding=utf-8 list=[] for i in range(1,101): list.append(i) # print(list) tempList=[] newList=[] whi ...
- Python之旅.第三章.函数3.26
一.函数: 1.为什么要有函数?什么是函数? 1.组织结构不清晰,可读性差 2.代码冗余 3.管理维护的难度极大,扩展性 具备某一个功能的工具就是程序的中函数 事先准备工具的过程---->函数的 ...
- LeetCode & Q189-Rotate Array-Easy
Array Description: Rotate an array of n elements to the right by k steps. For example, with n = 7 an ...
- 第一次制作和使用图标字体-IcoMoon
开题:之前就有所耳闻,最近两天第一次运用到图标字体.刚开始嘛,一脸懵逼的状态.成功运用之后就来记录一下使用过程咯! 1. 打开在线生成工具:https://icomoon.io/app/#/selec ...
- java对象转字节数组,获取泛型类
对象转字节数组,字节数组在恢复成对象 Test.java class Test { public static void main(String args[]) throws IOException, ...
- Linux网络配置(setup)
新装的Linux系统,想要快捷的网络配置,首选setup命令. 1.设置setup为中文. echo LANG="zh_CN.UTF-8" > /etc/sysconfig/ ...
- 官网jquery压缩版引用地址:
3.1.1版本 <!DOCTYPE html> <html lang="en"> <head> <meta charset="U ...