HGOI20180831 NOIP2018模拟
input1:
4
4 4 4 4
3 2 4 5
4 5 5 5
1 7 3 2
output1:
Yes
Yes
Yes
No
好的吧数学题QwQ考场上没人做出来qwq
就是判断两个矩形能否互相放到对方里面
后来想了想这道题怎么那么简单,判断边长不就得了吗?
虽然想到这道题是T2但还是傻到交一个可能0分的程序上去。。。(详见说明)
于是就有这么多代码。。。
- 大矩形的长大于小矩形的长,宽大于小矩形的宽,这时肯定可以放得下去;
- 大矩形的对角线小于小矩形的对角线,那么也就没有地方容下小矩形了,这时判定否;
70pts code:
# include <bits/stdc++.h>
using namespace std;
int main()
{
freopen("girls.in","r",stdin);
freopen("girls.out","w",stdout);
int n; scanf("%d",&n);
for (int i=;i<=n;i++) {
int a,b,c,d;
scanf("%d%d%d%d",&a,&b,&c,&d);
if (a>b) swap(a,b);
if (c>d) swap(c,d);
if (a<=c&&b<=d) printf("Yes\n");
else if (c<=a&&d<=b) printf("Yes\n");
else printf("No\n");
}
return ;
}
然后70pts
后来发现这是有反例的qwq?
斜着放?
像这样:
这样的话额。。好像小长方形略长一点好像是可以放下的qwq(其实也可以结合生活经验)
好的吧
这个时候我们发现并不能直接下结论。。要推倒。。
- 当小矩形的长大于大矩形的长时,此时斜放也可能放进大矩形,所以我们进行以下计算。
具体怎么算呢?
放个图:
思路:求出L1,L2验证以L1,L2构成直角三角形的斜边比y大那么就行否则不行。
BC2=x2+y2又 CI2=a2 所以 BI2=BC2-CI2=x2+y2-a2
所以BI=sqrt(x2+y2-a2)
由△ABF≌DCH(显然AAS)
BF=CH=L1 而IG=CH(矩形)
所以在GF上有 BF+BI+IG=GF 代入得 2L1+BI=EH
所以 L1=(EH-BI)/2=(b-sqrt(x2+y2-a2))/2;
同理可知 L2=(GH-AJ)/2=(a-sqrt(x2+y2-b2))/2;
若Rt△CHD中有sqrt(CD)<sqrt(L12+L22)即 y2<L12+L22
则合法否则不合法。所以有这样一个程序:
- 大矩形的长大于小矩形的长,宽大于小矩形的宽,这时肯定可以放得下去;
- 大矩形的对角线小于小矩形的对角线,那么也就没有地方容下小矩形了,这时判定否;
- 当小矩形的长大于大矩形的长时,此时斜放也可能放进大矩形,所以我们进行以下计算。如上图,假如左下角的那个小三角形,L1与L2求出第三条边大于等于小矩形的宽的话,那么小矩形就可以(碰壁)的放进去。
100pts code:
# include <bits/stdc++.h>
using namespace std;
bool fun(int x,int y,int a,int b)
//(x,y)能否放到(a,b),(长,宽)
{
if (x<=a&&y<=b) return true;
if (x*x+y*y>a*a+b*b) return false;
double L1=(b-sqrt(x*x+y*y-a*a))/2.0;
double L2=(a-sqrt(x*x+y*y-b*b))/2.0;
if (L1*L1+L2*L2>=(double)y*y) return true;
else return false;
}
int main()
{
freopen("girls.in","r",stdin);
freopen("girls.out","w",stdout);
int T;scanf("%d",&T);
while (T--) {
int x,y,a,b;
scanf("%d%d%d%d",&x,&y,&a,&b);
if (x<y) swap(x,y);
if (a<b) swap(a,b);
if (fun(x,y,a,b)||fun(a,b,x,y)) printf("Yes\n");
else printf("No\n");
}
return ;
}
input1:
5 6
0 6 6 10 10
2 0 7 8 6
10 5 0 10 3
9 5 8 0 7
4 9 8 3 0
1 2 3
1 4 1
2 1 3
1 4 2
1 1 2
2 4 1
output1:
6
11
题目意思:给出一幅完全图每次操作删一条边求两点最短路。(其中删边操作小于200)
要求任意两点最短路显然想到floyd最快!!!
但是要删掉一条边啊。不好办。
考场上第一想法是那道我们做过的O(n4)的一道加一条权为0的边求最短路
(好像是luogu2018新春模拟赛的T2)
想强制在线。。(这是显然想法好吧,是完全图、稠密图想到dijkstra好伐)
然后看到数据范围啦么小想一把暴力就过了吧,然后打了一个dijkstra堆优化好像是O(mn log n)
然后愉快的发现好像要T qwq
好的,这样以来就是想强制离线可不可以做,改删边为加边。
(反着做)我设现在要加的边为s-->t 权为w,
首先更新s--->t的最短路O(1)
那么枚举两个点u和v更新这两个点的最短距离显然有3种方法
- u--->s--->t--->v
- u--->t---->s--->v
- u--->v
由于各个点最短路我是知道的了,那么这些求值就是O(1)的了加边更新复杂度为O(n2)
有不多于200个删边操作O(n3)显然是够的,查询的话就是O(1)
这就是离线的算法。
考场上打的n<=40000的暴力dijkstra没有删去将就着看看。
# include <bits/stdc++.h>
# define INF INT_MAX/
# define Rint register int
using namespace std;
const int MAXN=,MAXM=;
struct record{
int pre,to,w;
}a[MAXN*MAXN];
int e[MAXN][MAXN],n,m,tot=,head[MAXN];
struct qwq{
int c,x,y;
}q[MAXM];
int rec[MAXN][MAXN],mp[MAXN][MAXN],ans[MAXM];
inline int read()
{
int X=,w=; char c=;
while(c<''||c>'') {w|=c=='-';c=getchar();}
while(c>=''&&c<='') X=(X<<)+(X<<)+(c^),c=getchar();
return w?-X:X;
}
void adde(int u,int v,int w)
{
a[++tot].pre=head[u];
a[tot].to=v;
a[tot].w=w;
head[u]=tot;
}
struct ww{
int id,lenth;
bool operator <(const ww a) const{
if (lenth!=a.lenth) return lenth>a.lenth;
else return id>a.id;
}
};
priority_queue<ww> qq;
int d[MAXN];
bool vis[MAXN];
inline void dijkstra(int s,int t)
{
memset(vis,,sizeof(vis));
for (int i=;i<=n;i++) d[i]=INF;
d[s]=;
ww Node; Node.id=s;Node.lenth=;qq.push(Node);
while (!qq.empty()) {
ww Node=qq.top();qq.pop();
int u=Node.id;
if (vis[u]) continue;
vis[u]=true;
for (int i=head[u];i;i=a[i].pre) {
int v=a[i].to;
if (d[v]-a[i].w>d[u]) {
d[v]=d[u]+a[i].w;
ww N;N.id=v;N.lenth=d[v];
qq.push(N);
}
}
}
if (d[t]<INF) printf("%d\n",d[t]);
else printf("-1\n");
}
void work1()
{
int x,y,c;
for (int i=;i<=n;i++)
for (int j=;j<=n;j++)
{
scanf("%d",&x);
if (i==j) continue;
adde(i,j,x);e[i][j]=tot;
}
for (int i=;i<=m;i++) {
c=read();x=read();y=read();
if (c==) {
dijkstra(x,y);
continue;
}
a[e[x][y]].w=INF;
}
}
int main()
{
freopen("journey.in","r",stdin);
freopen("journey.out","w",stdout);
scanf("%d%d",&n,&m);
if (m<=) {
work1();
return ;
}
for (Rint i=;i<=n;i++)
for (Rint j=;j<=n;j++)
scanf("%d",&mp[i][j]),rec[i][j]=mp[i][j];
for (Rint i=;i<=m;i++) {
q[i].c=read();q[i].x=read();q[i].y=read();
if (q[i].c==) mp[q[i].x][q[i].y]=INF;
}
for (Rint k=;k<=n;k++)
for (Rint i=;i<=n;i++)
for (Rint j=;j<=n;j++)
mp[i][j]=min(mp[i][j],mp[i][k]+mp[k][j]);
for (Rint i=m;i>=;i--) {
if (q[i].c==) {
ans[++ans[]]=mp[q[i].x][q[i].y];
continue;
}
int s=q[i].x,t=q[i].y;
mp[s][t]=min(mp[s][t],rec[s][t]);
for (int u=;u<=n;u++)
for (int v=;v<=n;v++)
mp[u][v]=min(min(mp[u][v],mp[u][s]+mp[s][t]+mp[t][v]),mp[u][t]+mp[t][s]+mp[s][v]);
}
for (Rint i=ans[];i>=;i--)
if (ans[i]>=INF) printf("-1");
else printf("%d\n",ans[i]);
return ;
}
input1:
output1:
input2:
8
1 2
1 3
2 4
2 5
3 6
3 7
1 8
output2:
题目意思:是在一棵树上找到两个点使各个点到这两点的最大距离最小。
是真的不会做。。
那么就暴力本来想打LCA的结果发现floyd更快。。
就是暴力枚举那两个点,再枚举各个点到这两个点最小距离求最大值(就是按照题意模拟吧)
# include <bits/stdc++.h>
using namespace std;
const int MAXN=;
int mp[MAXN][MAXN];
int n;
inline int read()
{
int X=,w=; char c=;
while(c<''||c>'') {w|=c=='-';c=getchar();}
while(c>=''&&c<='') X=(X<<)+(X<<)+(c^),c=getchar();
return w?-X:X;
}
bool p[MAXN],vis[MAXN];
int main()
{
freopen("ob.in","r",stdin);
freopen("ob.out","w",stdout);
scanf("%d",&n);
for (int i=;i<=n;i++)
for (int j=;j<=n;j++)
if (i!=j) mp[i][j]=INT_MAX/;
for (int i=;i<=n-;i++) {
int u,v;
u=read();v=read();
mp[u][v]=; mp[v][u]=;
}
for (int k=;k<=n;k++)
for (int i=;i<=n;i++)
for (int j=;j<=n;j++)
if (k!=i&&i!=j&&j!=k) mp[i][j]=min(mp[i][j],mp[i][k]+mp[k][j]);
int ans=INT_MAX;
for (int t1=;t1<=n;t1++)
for (int t2=;t2<=n;t2++) {
if (t1==t2) continue;
int Max=;
for (int u=;u<=n;u++) Max=max(Max,min(mp[u][t1],mp[u][t2]));
ans=min(ans,Max);
}
printf("%d\n",ans);
return ;
}
话说考场上写了点奇怪的东西竟然没有T???
【话说如果做出来了就会update的】
- 60pts Floyd暴力模拟!!!(就是上面那种方法)
- 80pts(1) 期望树是随机的,那么默认树的直径是log级别很短,直接在直径上枚举两个点O(n log2n)-O(n3)
- 80pts(2) 考虑两个奖杯管辖范围有边界枚举一条边作为边界(u---v)u作为一棵子树,v作为一棵子树,分别求两棵树的直径求最小值O(n2)
- 100pts
显然奖杯在树的直径上(奖杯首先要将树的直径覆盖),
所以二分答案MID,表示从一个点扩展开去可以覆盖的范围
然后check的时候判断这两点扩展开去染色是否存在没有被染色的点存在,
有就是false没有就是true
其他方法:
- 100pts (2)奖杯在直径上,二分答案后取离直径上离端点距离答案的点,遍历 check 一遍
- 100pts (3)随便提一个节点为根,二分答案,深度最深的节点一定要被照顾到,所以最深的点往上跳 答案层即可,和其距离答案以内的点都删掉,再做一次。 此法可以拓展到 k 个奖杯。
- 100pts (4)在 80 分的基础上用树形 dp,记下每个点向下前三长和向上一格后不回该子树最长的路径 长度。子树内直径是前两长的和与该子树各个子树直径取 max;子树外直径是父节点向上一格 后不回该子树最长的路径长度,前两长不进入该子树的向下最长路径这三条取前两长加起来与 父节点以上的答案取 max。
# include <bits/stdc++.h>
# define Rint register int
using namespace std;
const int Root=,MAXN=;
struct rec{
int pre,to;
}a[MAXN<<];
bool col[MAXN];
int n,dep[MAXN],line[MAXN],head[MAXN],pre[MAXN],tot=,ans;
void adde(int u,int v) //加边
{
a[++tot].pre=head[u];
a[tot].to=v;
head[u]=tot;
}
int getpts() //求出最深点并且把dep赋值为0
{
int Max=,P=;
for (int i=;i<=n;i++)
if (Max<dep[i]) Max=dep[i],P=i;
memset(dep,,sizeof(dep));
return P;
}
void getline(int u) //求树的直径到line[]里面方便计算
{
memset(line,,sizeof(line));
while (pre[u]!=-) {
line[++line[]]=u;
u=pre[u];
}
line[++line[]]=u;
}
void dfs1(int u,int fat,int depth) //树的直径先一边任一点开始dfs到最深点s
{
dep[u]=depth;
for (Rint i=head[u];i;i=a[i].pre){
int v=a[i].to; if (v==fat) continue;
dfs1(v,u,depth+);
}
}
void dfs2(int u,int fat,int depth) //从s开始dfs到最深点t并记录每个点是从谁(pre前驱)走过来的方便搞出line[]
{
pre[u]=fat; dep[u]=depth;
for (Rint i=head[u];i;i=a[i].pre){
int v=a[i].to; if (v==fat) continue;
dfs2(v,u,depth+);
}
}
void draw(int u,int step,int fat) //u向外染色step步
{
col[u]=true; //col 是true表示染色 false没染色
if (step==) return;
for (Rint i=head[u];i;i=a[i].pre){
int v=a[i].to; if (v==fat) continue;
draw(v,step-,u);
}
}
bool check(int MID) //判断是否可行
{
memset(col,false,sizeof(col));
int Node1=line[+MID],Node2=line[line[]-MID]; //最深处要顾及到
draw(Node1,MID,-);
draw(Node2,MID,-);
for (Rint i=;i<=n;i++)
if (!col[i]) return false;
return true;
}
void ErFen() //二分答案
{
int l=,r=line[];
while (l<=r){
int mid=(l+r)>>;
if (check(mid)) r=mid-,ans=mid;
else l=mid+;
}
}
int main()
{
scanf("%d",&n);
if (n<=) { printf("0\n"); return ; } //特判,不用走都能看到
int u,v;
for (Rint i=;i<=n-;i++)
scanf("%d%d",&u,&v),adde(u,v),adde(v,u);
dfs1(Root,-,); int s=getpts();
memset(pre,,sizeof(pre));
dfs2(s,-,); int t=getpts();
getline(t);
ErFen();
printf("%d\n",ans);
return ;
}
HGOI20180831 NOIP2018模拟的更多相关文章
- [NOIP2018模拟赛10.16]手残报告
[NOIP2018模拟赛10.16]手残报告 闲扯 炉石乱斗模式美滋滋啊,又颓到好晚... 上来T2先敲了树剖,看T1发现是个思博DP,然后没过大样例,写个暴力发现还是没过大样例!?才发现理解错题意了 ...
- NOIP2018 模拟赛(二十二)雅礼NOI
Preface 这次的题目都是NOI+的题,所以大家的分数都有点惨烈. 依靠T1大力骗分水到Rank2 所以想看正解的话看这里吧 A. 「雅礼NOI2018模拟赛(一) Day1」树 看一眼题目感觉十 ...
- EZ 2018 06 17 NOIP2018 模拟赛(十九)
这次的题目难得的水,但是由于许多哲学的原因,第二题题意表述很迷. 然后是真的猜题意了搞了. 不过这样都可以涨Rating我也是服了. Upt:链接莫名又消失了 A. 「NOIP2017模拟赛11.03 ...
- EZ 2018 06 10 NOIP2018 模拟赛(十八)
好久没写blog&&比赛题解了,最近补一下 这次还是很狗的,T3想了很久最后竟然连并查集都忘写了,然后T2map莫名爆炸. Rating爆减......链接不解释 好了我们开始看题. ...
- 【HHHOJ】NOIP2018 模拟赛(二十四) 解题报告
点此进入比赛 得分: \(100+60+100\)(挺好的,涨了一波\(Rating\)) 排名: \(Rank\ 1\) \(Rating\):\(+115\) \(T1\):[HHHOJ13]金( ...
- [jzoj NOIP2018模拟11.02]
嗯T1忘记取模了,100到20 嗯T2忘记了那啥定理,暴力也写炸了,这题我认 嗯T3线段树合并分裂没有写炸,考场上就知道妥妥的70分.但是,分数出的时候听到有人说暴力也是70分,我???脸黑,枉我敲了 ...
- [jzoj NOIP2018模拟10.29]
OI生涯的最高分,来了纪中这么多天,在经历了这么多场“NOIP难度”的模拟赛之后,终于看到了真正的NOIP 今天考场上效率很高,很快码完了全部的题目,留下了足够的时间对拍和...发呆.不得不说看着电脑 ...
- NOIp2018模拟赛四十二
今天看标题终于回到了“NOIP模拟赛”,十分高兴啊! 然后一打开题目: ********** 所以今天又是一场NOIPlus模拟赛(微笑) 成绩:0+70+0=70 A题想了个贪心被myh两分钟cha ...
- NOIp2018模拟赛三十六
好久没打模拟赛了...今天一样是两道国集,一道bzoj题 成绩:13+0+95=108 A题开始看错题了...导致样例都没看懂,结果xfz提醒我后我理解了一个我自认为正确的题意(事实证明我和xfz都错 ...
随机推荐
- Spark内部流程图
转载自:https://blog.csdn.net/refuil/article/details/52055104
- 【LeetCode148】Sort List★★bug
1.题目描述: 2.解题思路: 本题是要堆一个链表进行排序,并且要求时间复杂度为 O(n log n).很明显,要用到分治的思想,用二分法进行归并排序:找到链表的middle节点,然后递归对前半部分和 ...
- springboot 定制错误页面
项目中经常遇到的异常情况 400-Bad Request 401-Unauthorized If the request already included Authorization credenti ...
- 20155237 2016-2017-2 《Java程序设计》第十周学习总结
20155237 2016-2017-2 <Java程序设计>第十周学习总结 教材学习内容总结 计算机网络,是指分布在不同地理区域的计算机用通信线路互连起来的一个具有强大功能的网络系统.网 ...
- 20155331 Exp3 免杀原理与实践
20155331 Exp3 免杀原理与实践 基础问题回答 杀软是如何检测出恶意代码的? 1.基于特征码的检测,2.启发式恶意软件检测,3.基于行为的恶意软件检测. 免杀是做什么? 让病毒不被杀毒软件杀 ...
- 【Win32 API】利用SendMessage实现winform与wpf之间的消息传递
原文:[Win32 API]利用SendMessage实现winform与wpf之间的消息传递 引言 有一次心血来潮,突然想研究一下进程间的通信,能够实现消息传递的方法有几种,其中win32ap ...
- 汇编-MOV指令
知识点: MOV指令 基址 内联汇编 把OD附加到资源管理器右键菜单 一.MOV指令 aaa=0x889977;//MOV DWORD PTR DS:[0x403018],0x8899 ...
- 微信小程序云开发之云函数创建
云函数 云函数是一段运行在云端的代码,无需管理服务器,在开发工具内编写.一键上传部署即可运行后端代码. 小程序内提供了专门用于云函数调用的 API.开发者可以在云函数内使用 wx-server-sdk ...
- 【ORACLE】oracle11g单实例安装
-- 上传安装包 p13390677_112040_Linux-x86-64_1of7.zip p13390677_112040_Linux-x86-64_2of7.zip -- 解压安装包 unzi ...
- JavaScript快速入门-ECMAScript本地对象(Number)
Number 对象是原始数值的包装对象. 创建一个Number对象:var myNum=new Number(value); 注意: 1.参数 value 是要创建的 Number 对象的数值,或是要 ...