目录

一.题目

1.队列变换

1.1.题目描述

1.2.题解

1.3.Code

2.跨栏

2.1.题目描述

2.2.题解

2.3.Code

3.三角形

3.1.题目描述

3.2.题解

3.3.Code

二.总结

谢谢!


一.题目

1.队列变换

1.1.题目描述

传送门

1.2.题解

这道题挺灵活的,可以当做一个模板来记住可蒟蒻我当时就是没想到

根据题目描述可以知道,每操作一次相当于操作一行或一列,所以我们把每一行和每一列都请个代表出来,为了方便,代表们就是第一行和第一列。我们通过变换将代表们都变成同一个方向,如图:

(代表)R (代表)R (代表)R
(代表)R X X
(代表)R X X

那么那一个讨厌的站反的人就存在于三个地方:

1. (1,1):必须满足非代表的地方朝向是L,降第一行和第一列翻转即可

2. 除了(1,1)的代表:必须满足代表所在的那一行或那一列的人朝向都是L,其他人的的朝向都是R

3. 非代表的人:必须满足除了他自己站反以外,其他人都是R。

如果都不满足,输出-1即可。

模板:对于每次操作都要改变一个区间的题目,把每个改变的区间都请个代表出来。

1.3.Code

#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;#define M 1005int n, a[M][M], ansx, ansy, sum;
char c;int main (){scanf ("%d", &n);for (int i = 1; i <= n; i ++){scanf ("\n");for (int j = 1; j <= n; j ++){scanf ("%c", &c);a[i][j] = c == 'R' ? 1 : 0;}}for (int i = 1; i <= n; i ++){if (a[1][i]){for (int j = 1; j <= n; j ++)a[j][i] = (a[j][i] + 1) % 2;}}for (int i = 2; i <= n; i ++){if (a[i][1]){for (int j = 1; j <= n; j ++)a[i][j] = (a[i][j] + 1) % 2;}}bool flag = 0, f = 0;for (int i = 2; i <= n; i ++){for (int j = 2; j <= n; j ++){if (! a[i][j])flag = 1;if (a[i][j]){sum ++;if (! f)ansx = i, ansy = j, f = 1;elseansx = -1, ansy = -1;}}}if (! flag){printf ("1 1\n");return 0;}if (ansx > 0){printf ("%d %d\n", ansx, ansy);return 0;}if (sum >= n){printf ("-1\n");return 0;}for (int i = 2; i <= n; i ++){int s = 0;for (int j = 2; j <= n; j ++)s += a[j][i];if (s == n - 1){printf ("1 %d\n", i);return 0;}}for (int i = 2; i <= n; i ++){int s = 0;for (int j = 2; j <= n; j ++)s += a[i][j];if (s == n - 1){printf ("%d 1\n", i);return 0;}}printf ("-1\n");return 0;
}

2.跨栏

2.1.题目描述

传送门

2.2.题解

这道题是全场最难的题目,我可能有点口胡。

算法:set加扫描线,时间复杂度:

通过题目中说的只要删除一条线就一定能使其它线不相交,那么只要找到两条相交的线,其中一根就一定是要删除的线。关键是怎么找呢?

先来讨论一下怎么判断线的相交,这里要用到叉乘:

不会的先自己了解一下。

我们现在要判断两条线段是否交叉,我们可以取一条线段的一个端点和其他一条线段的两个段点分别连接,如图:

如果P1Q2和P1Q1两条线段的叉乘值的符号和P1Q1和P1P2两条线段叉乘值的符号相同,就可以判断出来P2和Q2分别在线段P1Q1的两面。

再同理,连另一条线段:

都判断一下就行了。如果两种情况都满足符号相同,就说明两条线段相交。

再来讨论如何找出两条相交的线段:

我们用set存储每一条线段。

我们要先把每一条线按横坐标从小到大排序,如果横坐标相同就按纵坐标从小到大排序。

然后用一条扫描线从左到右扫描,每扫描到一条线段的左端点,那么在将这条线段加入set之前,先判断一下这条线段是否和它左右的两条线段相交(左右两条线段都存在在set中,先用lower_bound找到这条线段加入后的位置,就是这个位置和前面那个位置就是这条线段的左右两条线段);每扫描到一条线段的右端点,就要删除线段,那么在删除线段的时候就判断这个线段的左右两条线段是否相交就行了。

最后找到相交的两条线段了,通过找其中一条线段与其他线段的相交次数就能确定是这两条线段中那条线段了。一定是相交次数大于1的那一条线段。

确实有点绕,然看代码还挺好理解的。

2.3.Code

#include <cstdio>
#include <cstring>
#include <iostream>
#include <vector>
#include <set>
#include <cstdlib>
#include <algorithm>
using namespace std;#define M 100005
#define LL long longstruct Point{LL x, y;int Index;
};
struct node {Point a, b;int nodeindex;
};
int n, ans1, ans2;
double X;
set <node> Se;
vector <node> S;
vector <Point> P;bool operator < (Point A, Point B){if (A.x == B.x)return A.y < B.y;return A.x < B.x;
}
int pd (LL A){if (! A)return 0;return A > 0 ? 1 : -1;
}
int operator * (Point A, Point B){return pd ((A.x * B.y) - (A.y * B.x));
}
Point operator - (Point A, Point B){Point p;p.x = A.x - B.x, p.y = A.y - B.y;return p;
}
bool itcc (node A, node B){Point p1 = A.a, q1 = A.b, p2 = B.a, q2 = B.b;return ((q2 - p1) * (q1 - p1)) * ((q1 - p1) * (p2 - p1)) >= 0 && ((q1 - q2) * (p2 - q2)) * ((p2 - q2) * (p1 - q2)) >= 0;
}
double eval (node A){if (A.a.x == A.b.x)return A.a.y;return A.a.y + (A.b.y - A.a.y) * (X - A.a.x) / (A.b.x - A.a.x);
}
bool operator < (node A, node B){return A.nodeindex != B.nodeindex && eval (A) < eval (B);
}
bool operator == (node A, node B){return A.nodeindex == B.nodeindex;
}
int main (){scanf ("%d", &n);for (int i = 0; i < n; i ++){node ss;scanf ("%lld %lld %lld %lld", &ss.a.x, &ss.a.y, &ss.b.x, &ss.b.y);ss.nodeindex = ss.a.Index = ss.b.Index = i;S.push_back (ss);P.push_back (ss.a), P.push_back (ss.b);}sort (P.begin (), P.end ());for (int i = 0; i < P.size (); i ++){ans1 = P[i].Index; X = P[i].x;set <node>::iterator it = Se.find (S[ans1]);if (it != Se.end ()){set <node>::iterator hou = it;hou ++;set <node>::iterator qian = it;if (hou != Se.end () && qian != Se.begin ()){qian --;if (itcc (S[qian -> nodeindex], S[hou -> nodeindex])){ans1 = qian -> nodeindex, ans2 = hou -> nodeindex;break;}}Se.erase (it);}else{set <node>::iterator it = Se.lower_bound (S[ans1]);if (it != Se.end () && itcc (S[it -> nodeindex], S[ans1])){ans2 = it -> nodeindex;break;}if (it != Se.begin ()){it --;if (itcc (S[it -> nodeindex], S[ans1])){ans2 = it -> nodeindex;break;}}Se.insert (S[ans1]);}}if (ans1 > ans2)swap (ans1, ans2);int ans2_count = 0;for (int i = 0; i < n; i ++){if (S[i].nodeindex != ans2 && itcc (S[i], S[ans2]))ans2_count ++;}if (ans2_count > 1)printf ("%d\n", ans2 + 1);elseprintf ("%d\n", ans1 + 1);return 0;
}

3.三角形

3.1.题目描述

题目描述

平面上有n行m列,一共n*m个方格,从上到下依次标记为第1,2,...,n行,从左到右依次标记为第1,2,...,m列,方便起见,我们称第i行第j列的方格为(i,j)。小Q在方格中填满了数字,每个格子中都恰好有一个整数a_{i,j}。小Q不 喜欢手算,因此每当他不想计算时,他就会让你帮忙计算。小Q一共会给出q个询问,每次给定一个方格(x,y)和一个整数k(1<=k<=min(x,y)),你需要回答由(x,y),(x-k+1,y),(x,y-k+1)三个格子构成的三角形边上以及内部的所有格子的a的和。

输入格式

第一行包含6个正整数n,m,q,A,B,C(1<=n,m<=3000,1<=q<=3000000,1<=A,B,C<=1000000) 其中n,m表示方格纸的尺寸,q表示询问个数。 为了防止输入数据过大,a和询问将由以下代码生成:

unsigned int A,B,C;
inline unsigned int rng61(){A ^= A << 16;A ^= A >> 5;A ^= A << 1;unsigned int t = A;A = B;B = C;C ^= t ^ A;return C;
}
int main(){scanf("%d%d%d%u%u%u", &n, &m, &q, &A, &B, &C);for(i = 1; i <= n; i++)for(j = 1; j <= m; j++)a[i][j] = rng61();for(i = 1; i <= q; i++){x = rng61() % n + 1;y = rng61() % m + 1;k = rng61() % min(x, y) + 1;}
}

输出格式

为了防止输出数据过大,设f_i表示第i个询问的答案,则你需要输出一行一个整数,即:

输入样例

3 4 5 2 3 7

输出样例 

3350931807

3.2.题解

殊不知这道题可能是最简单的一道题,可惜当时我没认真读题!

可以从题目描述中看出,每个要求的三角形都是等腰直角三角形,就是这样:

图中红色部分就是要求的三角形,我们可以通过图中的大矩形减去那个灰色的梯形多边形得到三角形。

怎么求大矩形和梯形多边形中所有数的和呢?很明显,二维的前缀和呀!

怎么样,一目了然吧。

3.3.Code

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>
#include <cstdlib>
using namespace std;
const int MAXN =3003;
#define ll unsigned int
unsigned int A,B,C,x,y,k;
unsigned int a[3003][3003];
ll d[3000003];
int n , m , q;
inline unsigned int rng61(){A ^= A << 16;A ^= A >> 5;A ^= A << 1;unsigned int t = A;A = B;B = C;C ^= t ^ A;return C;
}
ll sum[3003][3003] , sum2[MAXN][MAXN] , sumh[MAXN][MAXN];
int main(){//freopen("triangle.in","r",stdin);//freopen("triangle.out","w",stdout);scanf("%d%d%d%u%u%u", &n, &m, &q, &A, &B, &C);for( int i = 1; i<= n; i++){for( int j = 1; j <= m; j++){a[i][j] = rng61();//求前缀和sum[i][j] = sum[i][j-1] + sum[i-1][j] - sum[i-1][j-1] + a[i][j];sumh[i][j] = sumh[i][j-1] + a[i][j];sum2[i][j] = sum2[i-1][j+1] + sumh[i][j];}sum2[i][0] = sum2[i-1][1];}d[0] = 1;for( int i = 1 ; i <= q ; i ++ )d[i] = d[i-1] * 233;ll ans = 0;for( int i = 1; i<= q; i++){x = rng61() % n + 1;y = rng61() % m + 1;k = rng61() % min(x, y) + 1;ll tot = d[q-i] * ( sum[x][y] - sum[x-k][y] - (sum2[x][y-k] - sum2[x-k][y] ) ) ;ans = ans + tot;}printf( "%u" , ans );return 0;
}

二.总结

这次考试可谓暴露了我许多问题,我认为主要是自己没有拼尽全力,读题没有整体把握,有以下几点改善:

1. 每次考试要一直集中精力,就算骗分也要做,实在坚持不住可以去厕所洗脸;

2. 一开始要用半个小时读题并理解每一道题,整体把握;

3. 想思路时不要太局限,图论和数论要发散思维,而且完全有可能题目本身根本没有什么算法,就像第一题。

检查的时候要做到以下几点:

1.最后十分钟检查,别补程序
2.列检查清单:1.肉眼:长整型、变量名;2.动手:造小样例;3.生成极限数据测试是否超时;4.写暴力对拍,生成比较特殊的情况
每次考试结束要深层分析错误,要把每次考试都当做真正的NOIP比赛一般,别掉以轻心。

每日的练靶,我瞄准的就是NOIP提高组。

谢谢!

8.15.NOIP2019模拟赛总结——2019暑假篇相关推荐

  1. 「CSP-S模拟赛」2019第四场

    「CSP-S模拟赛」2019第四场 T1 「JOI 2014 Final」JOI 徽章 题目 考场思考(正解) T2 「JOI 2015 Final」分蛋糕 2 题目 考场思考(正解) T3 「CQO ...

  2. ssl模拟赛(2019.4.27)

    成绩 rank是有算其他大爷的 rank name score T1 T2 T3 T4 1 L Y F LYF LYF 320 100 100 100 20 2 H K Y HKY HKY 296 1 ...

  3. 野鸡NOI.AC模拟赛【2019.10.26】

    前言 截止至2019.10.2614:222019.10.26\ \ \ \ 14:222019.10.26    14:22 成绩 正题 T1:NOI.AC−T1:NOI.AC-T1:NOI.AC− ...

  4. 【模拟赛】2019 蓝桥杯省赛 A 组模拟赛(一)

    A(填) 阶乘位数 蒜头君对阶乘产生了兴趣,他列出了前 10 个正整数的阶乘以及对应位数的表: 对于蒜头君来说,再往后就很难计算了.他试图寻找阶乘位数的规律,但是失败了.现在请你帮他计算出第一个正整数 ...

  5. 学校初一模拟赛(2019.3.2)

    今天,我们学校给我们初一的蒟蒻来了一次模拟赛. T1:青蛙跳荷叶 题目 从前,有一个小青蛙决定去荷叶上练习跳跃.现在有n个荷叶排成一排,小青蛙一开始在最左边的荷叶(一号荷叶)上,当然,这个青蛙是很牛X ...

  6. [NOIP2019模拟赛]LuoguP4261白金元首与克劳德斯

    题目描述 给出坐标系中n个矩形,类型1的矩形每单位时间向x轴正方向移动1个单位,类型2的矩形向y轴正方向,初始矩形不重叠,一个点被矩形覆盖当且仅当它在矩形内部(不含边界),求$(-\infty ,+\ ...

  7. 欢乐纪中B组周五模拟赛【2019.3.8】

    前言 成绩 RankRankRank是有算别人的 RankRankRank PersonPersonPerson ScoreScoreScore AAA BBB CCC 222 2017myself2 ...

  8. ssl提高组周六模拟赛【2019.3.2】

    前言 Rank1Rank1Rank1耶 成绩 RankRankRank是有算别人的 只放前Rank10Rank10Rank10 RankRankRank PersonPersonPerson Scor ...

  9. 学校初一模拟赛(2019.4.7)

    成绩 rank name score T1 T2 T3 T4 1 f y fy fy 230 100 100 20 10 2 t j h tjh tjh 210 100 0 100 10 3 w j ...

最新文章

  1. Hello Shell
  2. 零基础python入门书籍-零基础学Python,不容错过的入门书籍
  3. C语言 使用递归函数计算1到n之和
  4. 不小心删表删库了,还能救
  5. 【POJ - 1664】放苹果 (递归经典题 或 dp 或 母函数)
  6. qt使用动画提示正在载中
  7. mysql磁盘无法挂载,linux – 无法挂载磁盘(VFS:找不到ext4文件系统)
  8. mysql check table_mysql check table
  9. 转帖Masonry介绍与使用实践(快速上手Autolayout)
  10. 尘埃落定!熊猫互娱近20亿元投资纠纷已解决
  11. jQuery琐碎笔记
  12. 排序 —— 希尔排序(Shell sort)
  13. 网络设备中的路由器的作用,如何设置路由器,上网、IP分配、黑白名单、访问量...
  14. qt 日历类 不可输入当前日期之后的日期_UI设计组件时间选择器,日历设计从未如此简单!...
  15. 写给非网工的CCNA教程(1)IP地址和MAC地址
  16. java毕业设计补课管理系统Mybatis+系统+数据库+调试部署
  17. 知识众筹服务平台网盘[入口]
  18. 美国会委员会建议禁止中国国企收购美国资产
  19. android 检查xposed,[原创]利用Xposed躲过Xposed检测
  20. 如何开启红米手机4X的ROOT超级权限

热门文章

  1. 第17篇 账户管理(助记词)
  2. mysql如何设置密码
  3. win10里C盘的Program Files和 Program Files(x86)的区别
  4. JavaScript进阶
  5. icode五级训练场函数入门1-9
  6. PDF文件一键压缩工具V1.0-免费版
  7. 阿里2020.4.1实习笔试题——攻击怪兽
  8. 传感器检测与转换技术QY-CG810B
  9. 让你少走弯路 建站新手必看的十大忠告
  10. 北京高新技术企业申报新增要求及解决办法