11-1模拟赛 By cellur925
期望得分:70+100+60
实际得分:70+20+60 \(qwq\)。
T1:有一个 \(n\) × \(n\) 的 \(01\) 方格, 图图要从中选出一个面积最大的矩形区域, 要求这个矩形区域不能有超过 \(k\) 个 \(1\)。
开始只会\(O(n^4)\)算法,即枚举左上角和右下角,然后去写了T2&T3,回来想了一个多小时大概,还是没想出...但是造了大数据验证了一下暴力应该是没问题的。
70分暴力:
#include<cstdio>
#include<algorithm>
using namespace std;
int n,k,ans;
int mapp[600][600];
int main()
{
freopen("game.in","r",stdin);
freopen("game.out","w",stdout);
scanf("%d%d",&n,&k);
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
scanf("%d",&mapp[i][j]);
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
mapp[i][j]+=mapp[i-1][j]+mapp[i][j-1]-mapp[i-1][j-1];
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
for(int l=1;l<=n&&i-l+1>=1;l++)
for(int r=1;r<=n&&j-r+1>=1;r++)
{
int ii=i-l+1;
int jj=j-r+1;
int qwq=mapp[i][j]+mapp[ii-1][jj-1]-mapp[ii-1][j]-mapp[i][jj-1];
if(qwq>k) continue;
ans=max(ans,l*r);
}
printf("%d",ans);
return 0;
}
正解:很巧妙的想法:我们不需枚举那么多,有些是重复的。因为矩阵的二维前缀和是有单调性的。什么意思?我们枚举矩阵的上下界,然后只枚举一个右边界,左边界从1开始向右推进,显然在开始时刻包含的1最多,在不断向右推进的过程中包含的1越来越少,当找到一个满足\(k\)的时刻我们便停止向右推进,这时一定保证最优。因为右面的情况会越来越少。
#include<cstdio>
#include<algorithm>
using namespace std;
int n,k,ans;
int f[1000][1000];
int ask(int a,int b,int c,int d)
{
return f[c][d]+f[a-1][b-1]-f[a-1][d]-f[c][b-1];
}
int main()
{
scanf("%d%d",&n,&k);
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
scanf("%d",&f[i][j]);
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
f[i][j]+=f[i-1][j]+f[i][j-1]-f[i-1][j-1];
for(int i=1;i<=n;i++)
for(int j=i;j<=n;j++)
{
int l=1;
for(int r=1;r<=n;r++)
{
while(ask(i,l,j,r)>k) l++;
ans=max(ans,(r-l+1)*(j-i+1));
}
}
printf("%d\n",ans);
return 0;
}
主要是这个单调性,它就是很显然的东西,但是如果不注意它的话就真找不到正解==。
T2:他正在玩一款策略游戏, 地图由 \(n\) 座城市组成, 并由 \(n - 1\) 条无向带权边连接成树形结构。 为了解决物资补给, 图图需要在这 \(n\) 座城市选出若干座城市建立机场, 其中在第 \(i\) 座城市建立机场的代价是 \(cost[i]\)。
建立机场之后, 每座城市得到补给的代价为该城市到最近机场的距离。 而他总共花费的代价即为建立机场的代价与每座城市得到补给的代价之和, 当然他想让这个代价最小。
考场上读完题后感觉是自己做过的原题然后就惨惨了。事后感觉一点也不一样啊,只是看起来很像⑧了(摔)。事实是考场上几乎不会出原题的,如果感觉像一定要一再尝试否认自己。不能盲目自信==。
这种最优化&在树上背景,大多是树形dp。我竟然从没向这想过(。首先我们考虑一条链的情况,\(f[i]\)表示前\(i\)个城市的代价均已计算,最后一个机场设在第\(i\)个城市的最小花费。转移:
https://cdn.luogu.org/upload/pic/41397.png
如果状态设计出来,这个转移应该还是不难理解的。考虑如何扩展到树的情况,一般我们设计树形dp的状态时,有诸如\(dp[i]\)为以\(i\)为根的子树\(balabala\)...的表述。
我们考虑设计这样一个状态:\(f[i][j]\)表示以\(i\)为根的子树,当前距离\(i\)最近的机场设在了\(j\),子树内所有城市花费之和的最小值,另设一个\(g[i]\)保存\(min{f[i][j]}\)。那么转移:有两部分我们是一定要花费的,\(i\)到\(j\)的距离和在\(j\)点建造的花费。其他:枚举\(i\)子树内的所有儿子\(v\),在\(g[v]\)和\(f[v][j]\)-\(val[j]\)中寻求最小。(减去\(val[j]\)是为了防止算多。)那么转移即为这样:
for(int j=1;j<=n;j++)
{
f[u][j]=val[j]+dis[u][j];
for(int i=head[u];i;i=edge[i].next)
{
int v=edge[i].to;
if(v!=fa) f[u][j]+=min(g[v],f[v][j]-val[j]);
}
}
可以看出我们还需要计算一下两点间的距离:因为是在一棵树上,因为复杂度被控制在不\(n^2\)内,那么我们可以从每个点出发进行一遍\(dfs\)求出这个距离。(感觉\(std\)的这个想法好巧妙啊x)
for(int i=1;i<=n;i++) dfs(i,0,i);
void dfs(int u,int fa,int s)
{
for(int i=head[u];i;i=edge[i].next)
{
int v=edge[i].to;
if(v==fa) continue;
dis[s][v]=dis[s][u]+edge[i].val;
dfs(v,u,s);
}
}
完整代码
#include<cstdio>
#include<algorithm>
#include<cstring>
#define maxn 2600
using namespace std;
int n,tot;
int head[maxn],val[maxn],g[maxn],dis[maxn][maxn],f[maxn][maxn];
struct node{
int to,next,val;
}edge[maxn<<1];
void add(int x,int y,int z)
{
edge[++tot].to=y;
edge[tot].next=head[x];
head[x]=tot;
edge[tot].val=z;
}
void dfs(int u,int fa,int s)
{
for(int i=head[u];i;i=edge[i].next)
{
int v=edge[i].to;
if(v==fa) continue;
dis[s][v]=dis[s][u]+edge[i].val;
dfs(v,u,s);
}
}
void TreeDP(int u,int fa)
{
for(int i=head[u];i;i=edge[i].next)
{
int v=edge[i].to;
if(v!=fa) TreeDP(v,u);
}
for(int j=1;j<=n;j++)
{
f[u][j]=val[j]+dis[u][j];
for(int i=head[u];i;i=edge[i].next)
{
int v=edge[i].to;
if(v!=fa) f[u][j]+=min(g[v],f[v][j]-val[j]);
}
}
g[u]=f[u][1];
for(int i=1;i<=n;i++) g[u]=min(g[u],f[u][i]);
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d",&val[i]);
for(int i=1;i<=n-1;i++)
{
int x=0,y=0,z=0;
scanf("%d%d%d",&x,&y,&z);
add(x,y,z),add(y,x,z);
}
for(int i=1;i<=n;i++) dfs(i,0,i);
TreeDP(1,0);
printf("%d\n",g[1]);
return 0;
}
T3:他计划去 \(Bzeroth\) 的精灵王国去旅游, 精灵王国由 \(n\) 座城市组成, 第 \(i\) 座城市有 \(3\) 个属性 \(x[i]\), \(w[i]\), \(t[i]\)。
在精灵王国的城市之间穿行只能依靠传送阵, 第 \(i\) 座城市的传送阵可以将他从城市 \(i\) 传送到距离城市 \(i\) 不超过 \(w[i]\)的任意一个城市, 并需要 \(t[i]\)的时间完成传送。 现在他知道了每个城市的坐标 \(x[i]\), 想知道他从城市 \(s\) 到城市 \(t\) 的最小时间。
唔...读完题后感觉只会打\(60\)分的暴力,建边最坏复杂度\(O(n^2)\),跑\(dijistra\)复杂度\(O(mlogn)\),总复杂度近似为\(O(n^2logn)\)。
\(60\)分暴力:
#include<cstdio>
#include<algorithm>
#include<queue>
#include<cstring>
#define maxn 153000
using namespace std;
typedef long long ll;
int n,s,t,tot;
int pos[maxn],dist[maxn],w[maxn],head[maxn];
ll dis[maxn];
bool vis[maxn];
struct node{
int to,next,val;
}edge[6300000];
void add(int x,int y,int z)
{
edge[++tot].to=y;
edge[tot].next=head[x];
head[x]=tot;
edge[tot].val=z;
}
void dijkstra()
{
priority_queue<pair<ll,int> >q;
q.push(make_pair(0,s));
for(int i=1;i<=n;i++) dis[i]=2e9;
dis[s]=0;
while(!q.empty())
{
int u=q.top().second;q.pop();
if(vis[u]) continue;
vis[u]=1;
for(int i=head[u];i;i=edge[i].next)
{
int v=edge[i].to;
if(dis[v]>dis[u]+edge[i].val)
{
dis[v]=dis[u]+edge[i].val;
q.push(make_pair(-dis[v],v));
}
}
}
}
int main()
{//60 pts
freopen("trip.in","r",stdin);
freopen("trip.out","w",stdout);
scanf("%d%d%d",&n,&s,&t);
for(int i=1;i<=n;i++) scanf("%d",&pos[i]);
for(int i=1;i<=n;i++) scanf("%d",&dist[i]);
for(int i=1;i<=n;i++) scanf("%d",&w[i]);
for(int i=1;i<=n;i++)
{
int j=i+1;
while(pos[j]-pos[i]<=dist[i]&&j<=n)
{
add(i,j,w[i]);
j++;
}
j=i-1;
while(pos[i]-pos[j]<=dist[i]&&j>=1)
{
add(i,j,w[i]);
j--;
}
}
dijkstra();
printf("%lld\n",dis[t]);
return 0;
}
正解:这个复杂度的瓶颈其实就在建边上,首先很显然能建的边是一段连续的区间,我们可以优化用二分求得。然后我们可以从各点向这些连续区间连边!这就很像线段树的查询区间了,把这些区间在线段树上维护,那么从每个城市出发,会向\(O(logn)\)个区间连边,边数被降到了\(O(nlogn)\)。再跑\(dij\)就能稳过了。代码...写不出来,因为不会动态开点线段树(,先鸽了。
11-1模拟赛 By cellur925的更多相关文章
- 9.11 myl模拟赛
9.11 myl 模拟赛 100 + 100 + 0 第一题耗费了太多的时间,导致最后一题没有时间想,直接去写了暴力,而且出题人没有给暴力分.... Problem 1. superman [题目描述 ...
- NOIp2017真题模拟赛 By cellur925
果然我还是最菜的==不接受反驳 (先考了day2喵喵喵) Day2 T1:奶酪 期望得分:100分 实际得分:100分 考察:并查集 思路:这题其实之前做过了==.思路还是比较清晰的,读入时预处理出可 ...
- 2017.6.11 NOIP模拟赛
题目链接: http://files.cnblogs.com/files/TheRoadToTheGold/2017-6.11NOIP%E6%A8%A1%E6%8B%9F%E8%B5%9B.zip 期 ...
- 9-26模拟赛 By cellur925
1.计数 (count.cpp/c/pas)时间限制:1s内存限制:256MB[问题描述]给出 m 个数 a[1],a[2],…,a[m]求 1~n 中有多少数不是 a[1],a[2],…,a[m]的 ...
- NOIp 2015真题模拟赛 By cellur925
果然我还是最菜的==不接受反驳== Day1 T1:神奇的幻方 思路:直接模拟即可,由于当前放法只与上一放法有关系,用两个变量记录一下即可.10分钟内切掉== 预计得分:100分 实际得分:100分 ...
- 11.17 模拟赛&&day-2
/* 后天就要复赛了啊啊啊啊啊. 可能是因为我是一个比较念旧的人吧. 讲真 还真是有点不舍. 转眼间一年的时间就过去了. 2015.12-2016.11. OI的一年. NOIP gryz RP++. ...
- 2014.11.12模拟赛【美妙的数字】| vijos1904学姐的幸运数字
美妙的数字(number.c/.cpp/.pas) 题目描述 黄巨大认为非负整数是美妙的,并且它的数值越小就越美妙.当然0是最美妙的啦. 现在他得到一串非负整数,对于每个数都可以选择先对它做二进制非运 ...
- 2014.11.12模拟赛【最小公倍数】| vijos1047最小公倍数
最小公倍数(lcm.c/.cpp/.pas) 题目描述 给定两个正整数,求他们的最小公倍数. 样例输入 28 12 样例输出 84 数据范围 对于40%数据:1<=a,b<=10^9 对于 ...
- 11.7NOIP模拟赛解题报告
心路历程 预计得分:\(50 + 100 + 100\) 实际得分:\(50 + 100 +100\) T2 T3两道数据结构题美滋滋,然而写完就过去\(3h\)美滋滋 T1数学题学弟们都会做Orzz ...
- 11.6NOIP模拟赛解题报告
心路历程 预计得分:\(100 + 100 + 100 = 300\) 实际得分:\(100 +100 +100 = 300\) 学OI两年终于AK了一次qwq(虽然题目炒鸡水..) 纪念一下这令人激 ...
随机推荐
- react遇到的各种坑
标签里用到<label for>的,for 要写成htmlFor 标签里的class要写成className 组件首字母一定要大写 单标签最后一定要闭合 如果html里要空格转义, 注意不 ...
- ssh key 生成
1.设置好git的name和email $ git config --global user.name "姓名" $ git config --global user.email ...
- Linux就该这么学--命令集合4(文件目录管理命令)
1.touch命令用于创建空白文件与修改文件时间:(touch [选项] [文件]) 对于在Linux中的文件有三种时间: 更改时间(mtime):内容修改时间(不包括权限的) 更改权限(ctime) ...
- js 单例模式的实现方式----闭包和构造函数内部判断
闭包: var singleton = function( fn ){ var result; return function(){ return result || ( result = fn .a ...
- checkbox 背景图片 纯CSS处理办法
CSS .table_container input[type="checkbox"] { background: #fff url(/img/blue.png); backgro ...
- [2017-10-26]Abp系列——DTO入参验证使用方法及经验分享
本系列目录:Abp介绍和经验分享-目录 声明式的入参验证逻辑 声明式入参验证主要使用了System.ComponentModel.DataAnnotations中提供的各种验证参数的Attribute ...
- linux内核container_of宏定义分析
看见一个哥们分析container_of很好,转来留给自己看 一.#define offsetof(TYPE, MEMBER) ((size_t) & ((TYPE *)0)->MEMB ...
- mysql的navicat注册码生成
首先下载安装Navicat在Navicat关闭的情况下运行注册机在注册机界面点击patch,选择Navicat安装目录下的Navicat.exe打补丁弹出破解成功后拔掉网线断网products选择my ...
- 恶心的struts标签,等我毕业设计弄完了,瞧我怎么收拾你。
1.从java action中到页面中获取变量值的struts标签 获取从bean中定义的对象中属性的值: <s:property value="#request.cardTo.acc ...
- webrtc 学习资源
http://www.cnblogs.com/lingyunhu/tag/webrtc%20android%20ios/