T1 [JZOJ2908] 矩阵乘法

题目描述

  给你一个 N*N 的矩阵,不用算矩阵乘法,但是每次询问一个子矩形的第 K 小数。

数据范围

  对于 $20\%$ 的数据,$N \leq 100$,$Q \leq 10^3$

  对于 $40\%$ 的数据,$N \leq 300$,$Q \leq 10^4$

  对于 $60\%$ 的数据,$N \leq 400$,$Q \leq 3 \times 10^4$

  对于 $100\%$ 的数据,$N \leq 500$,$Q \leq 6 \times 10^4$

分析

  作为一个数据结构菜鸡怎么可能会做这种题目

  本题有多种写法我都写不来,代码中给出是二维树状数组+整体二分,此外还有主席树+分块没学过啊,等等

  基于划分树的边二分边查询的思想,我们可以二分所有询问,一开始二分同样的一个数值,即查询一个子矩形中小于等于 $mid$ 的数的个数,这里用二维树状数组进行统计

  二分后所有节点会分成两边,只需要将所有询问与矩阵中的数字分别递归即可

  时间复杂度为 $O((q+n^2) \, log^2 n \, log \, q)$

  实际上由于二维树状数组的常数非常小,所以这个算法是可以通过的

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <queue>
using namespace std;
#define inf 0x3f3f3f3f
#define N 502
#define M 60005 inline int read() {
int x = , f = ; char ch = getchar();
while (!isdigit(ch)) {if (ch == '-') f = -; ch = getchar();}
while ( isdigit(ch)) {x = x * + ch - ''; ch = getchar();}
return x *= f;
} int n, m, t[N][N];
int id[M], cur[M], ans[M], q1[M], q2[M]; struct Mat {int x, y, v;} g[N * N];
bool cmp(Mat a, Mat b) {return a.v < b.v;}
struct Query {int x1, y1, x2, y2, k;} q[M]; inline int lowbit(int x) {return x & -x;} inline void add(int x, int y, int v) {
for (int i = x; i <= n; i += lowbit(i))
for (int j = y; j <= n; j += lowbit(j))
t[i][j] += v;
} inline int pre(int x, int y) {
int sum = ;
for (int i = x; i; i -= lowbit(i))
for (int j = y; j; j -= lowbit(j))
sum += t[i][j];
return sum;
} inline int sub(int x1, int y1, int x2, int y2) {
int sum = pre(x2, y2);
sum -= pre(x1 - , y2) + pre(x2, y1 - );
sum += pre(x1 - , y1 - );
return sum;
} void solve(int l, int r, int ql, int qr) {
if (ql > qr) return;
if (l == r) {
for (int i = ql; i <= qr; i++) ans[id[i]] = g[l].v;
return;
}
int mid = (l + r) >> , cnt1 = , cnt2 = ;
for (int i = l; i <= mid; i++) add(g[i].x, g[i].y, );
for (int i = ql, j = id[i]; i <= qr; j = id[++i]) {
int sum = cur[j] + sub(q[j].x1, q[j].y1, q[j].x2, q[j].y2);
if (sum >= q[j].k) q1[++cnt1] = j;
else q2[++cnt2] = j, cur[j] = sum;
}
int cnt = ql - ;
for (int i = ; i <= cnt1; i++) id[++cnt] = q1[i];
for (int i = ; i <= cnt2; i++) id[++cnt] = q2[i];
for (int i = l; i <= mid; i++) add(g[i].x, g[i].y, -);
solve(l, mid, ql, ql + cnt1 - );
solve(mid + , r, ql + cnt1, qr);
} int main(){
n = read(); m = read();
for (int i = ; i <= n; i++)
for (int j = ; j <= n; j++) {
g[(i - ) * n + j].x = i;
g[(i - ) * n + j].y = j;
g[(i - ) * n + j].v = read();
}
sort(g + , g + n * n + , cmp);
for (int i = ; i <= m; i++) {
q[i].x1 = read(); q[i].y1 = read();
q[i].x2 = read(); q[i].y2 = read();
q[i].k = read(); id[i] = i;
}
solve(, n * n, , m);
for (int i = ; i <= m; i++)
printf("%d\n", ans[i]); return ;
}

T2 [JZOJ3410] Tree

题目描述

  Wayne 在玩儿一个很有趣的游戏。在游戏中,Wayne 建造了 N 个城市,现在他想在这些城市间修一些公路,当然并不是任意两个城市间都能修,为了道路系统的美观,一共只有 M 对城市间能修公路,即有若干三元组 (Ui, Vi,Ci) 表示 Ui 和 Vi 间有一条长度为 Ci 的双向道路。当然,游戏保证了,若所有道路都修建,那么任意两城市可以互相到达。

  Wayne 拥有恰好 N - 1 支修建队,每支队伍能且仅能修一条道路。当然,修建长度越大,修建的劳累度也越高,游戏设定是修建长度为 C 的公路就会有 C 的劳累度。当所有的队伍完工后,整个城市群必须连通,而这些修建队伍们会看看其他队伍的劳累情况,若劳累情况差异过大,可能就会引发骚动,不利于社会和谐发展。Wayne 对这个问题非常头疼,于是他想知道,这 N - 1 支队伍劳累度的标准差最小能有多少。

数据范围

  对于 $20\%$ 的数据,$M \leq 20$

  对于另外 $30\%$ 的数据,$C \leq 10$

  对于 $100\%$ 的数据,$N \leq 100$,$M \leq 2000$,$C \leq 100$

分析

  考场上写了个水法,后来发现似乎是正解喜闻乐见

  首先这是一道最小标准差生成树

  刚开始发现 $C$ 很小,感觉解法和这个有关,于是想到枚举平均数

  但是直接枚举出平均数是不存在的,考虑到标准差是个表示数据稳定性的量,所以可以在合理范围内枚举长度值,选取长度与之最接近的道路做生成树,然后算出真实平均值求标准差来更新答案

  由于所有道路的长度都是正整数,所以对于 $x \in (0.5k,0.5k+0.5) \; (k \in N)$,当 $k$ 取某固定值时,无论 $x$ 取何值,所有道路按长度与 $x$ 的差值从小到大排序的结果是相同的

  因此只需要每隔 $0.25$ 枚举一个长度值,当然也可以将所有道路长度都乘以 $4$

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <vector>
#include <queue>
using namespace std;
#define ll long long
#define inf 0x3f3f3f3f
#define N 105
#define M 2005 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;
} double ans = 1000000000.0;
int n, m, maxe, mine = inf;
int f[N], q[N]; struct Edge {int u, v, w, d;} e[M];
bool cmp(Edge a, Edge b) {return a.d < b.d;} int find(int x) {
if (x == f[x]) return x;
return f[x] = find(f[x]);
} int main() {
n = read(); m = read();
for (int i = ; i <= m; i++) {
e[i].u = read(); e[i].v = read(); e[i].w = read() * ;
maxe = max(maxe, e[i].w); mine = min(mine, e[i].w);
}
for (int k = mine; k <= maxe; k++) {
for (int i = ; i <= m; i++) e[i].d = abs(e[i].w - k);
sort(e + , e + m + , cmp);
int cnt = , sum = ; double now = ;
for (int i = ; i <= n; i++) f[i] = i;
for (int i = ; i <= m; i++) {
int x = find(e[i].u), y = find(e[i].v);
if (x == y) continue; f[x] = y;
q[++cnt] = i; sum += e[i].w / ;
if (cnt == n - ) break;
}
double avg = (double)sum / (double)(n - );
for (int i = ; i < n; i++)
now += (e[q[i]].w / 4.0 - avg) * (e[q[i]].w / 4.0 - avg);
now = sqrt(now / (n - ));
ans = min(ans, now);
}
printf("%.4lf", ans); return ;
}

T3 [JZOJ3682] Points and Segments

题目描述

  Lahub 在几何问题上准备得不充分,但是他听说这一年的 IOI 选拔夏令营中会出现许多几何问题。深陷恐惧的 Lahub 把他自己锁在了地下室里,并且开始思考这一类别的新题目。其中一个如下。
Lahub 想要在 OX 轴上画 n 条不同的线段 [li,ri]。线段可以是红色和蓝色其中任意一种。图画是“好”的当且仅当满足接下来的条件:

  对于每个 OX 轴上的点 x,考虑所有包含点 x 的线段,设有 rx 个红线段和 bx 个蓝线段包含点 x,必须满足不等式 |rx-bx|<=1。

  线段 [l,r] 包含点 x 当且仅当 l<= x<= r。

  Lahub 给你所有线段的左右端点,你不得不找到一个“好”的画法给他。

数据范围

  对于 $20\%$ 的数据,$N \leq 10$

  对于 $40\%$ 的数据,$N \leq 10^3$

  对于 $100\%$ 的数据,$N \leq 10^5$

分析

  根据差分的思想,一段区间被染色,就相当于 $l$ 加,$r+1$ 减

  首先当然要把点离散化,然后对于每个区间我们可以在 $l$ 和 $r+1$ 之间连一条无向边

  如果图中存在奇点(一定为偶数个),则可以从小到大组成若干对点,在每对点之间连一条虚边(任意两条虚边之间不存在重合部分),此时就形成了一个欧拉回路

  于是可以在图上跑一边欧拉回路,若经过某条边时方向向左,则对应区间被染成红色,反之则被染成蓝色,这样就能保证在每个点上红色和蓝色的覆盖次数之差的绝对值不超过 $1$

  因为这是个欧拉回路,覆盖每个点的红色区间和蓝色区间数量一定相等,且每个点最多被一条虚边覆盖,所以删去虚边后仍然符合题意

#include <cstdio>
#include <iostream>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <vector>
using namespace std;
#define inf 0x3f3f3f3f
#define N 200005 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, tot = , last;
int to[N << ], num[N << ], nxt[N << ], head[N];
int q[N], d[N], vis[N], used[N << ], ans[N >> ];
struct Data {int l, r;} t[N >> ]; void add(int u, int v, int w) {
to[++tot] = v; num[tot] = w;
nxt[tot] = head[u]; head[u] = tot;
} void dfs(int x) {
vis[x] = ;
for (int &i = head[x]; i; i = nxt[i])
if (!used[i]) {
used[i] = used[i ^ ] = ;
ans[num[i]] = (to[i] > x);
dfs(to[i]);
}
} int main(){
n = read();
for (int i = ; i <= n; i++) {
t[i].l = read(); t[i].r = read() + ;
q[++m] = t[i].l; q[++m] = t[i].r;
}
sort(q + , q + m + );
m = unique(q + , q + m + ) - q - ;
for (int i = ; i <= n; i++) {
t[i].l = lower_bound(q + , q + m + , t[i].l) - q;
t[i].r = lower_bound(q + , q + m + , t[i].r) - q;
add(t[i].l, t[i].r, i); add(t[i].r, t[i].l, i);
d[t[i].l]++; d[t[i].r]++;
}
for (int i = ; i <= m; i++)
if (d[i] & ) {
if (last) {
add(last, i, ); add(i, last, );
d[last]++; d[i]++; last = ;
}
else last = i;
}
for (int i = ; i <= m; i++) if (!vis[i]) dfs(i);
for (int i = ; i <= n; i++) printf("%d ", ans[i]); return ;
}

2019-08-23 纪中NOIP模拟A组的更多相关文章

  1. 2019-08-21 纪中NOIP模拟A组

    T1 [JZOJ6315] 数字 题目描述

  2. 2019-08-09 纪中NOIP模拟B组

    T1 [JZOJ1035] 粉刷匠 题目描述 windy有N条木板需要被粉刷. 每条木板被分为M个格子. 每个格子要被刷成红色或蓝色. windy每次粉刷,只能选择一条木板上一段连续的格子,然后涂上一 ...

  3. 2019-08-15 纪中NOIP模拟B组

    T1 [JZOJ3455] 库特的向量 题目描述 从前在一个美好的校园里,有一只(棵)可爱的弯枝理树.她内敛而羞涩,一副弱气的样子让人一看就想好好疼爱她.仅仅在她身边,就有许多女孩子想和她BH,比如铃 ...

  4. 2019-08-12 纪中NOIP模拟B组

    T1 [JZOJ4879] 少女觉 题目描述 “在幽暗的地灵殿中,居住着一位少女,名为古明地觉.” “据说,从来没有人敢踏入过那座地灵殿,因为人们恐惧于觉一族拥有的能力——读心.” “掌控人心者,可控 ...

  5. 2019-08-01 纪中NOIP模拟B组

    T1 [JZOJ2642] 游戏 题目描述 Alice和Bob在玩一个游戏,游戏是在一个N*N的矩阵上进行的,每个格子上都有一个正整数.当轮到Alice/Bob时,他/她可以选择最后一列或最后一行,并 ...

  6. 2019-08-25 纪中NOIP模拟A组

    T1 [JZOJ6314] Balancing Inversions 题目描述 Bessie 和 Elsie 在一个长为 2N 的布尔数组 A 上玩游戏. Bessie 的分数为 A 的前一半的逆序对 ...

  7. 2019-08-20 纪中NOIP模拟B组

    T1 [JZOJ3490] 旅游(travel) 题目描述 ztxz16如愿成为码农之后,整天的生活除了写程序还是写程序,十分苦逼.终于有一天,他意识到自己的生活太过平淡,于是决定外出旅游丰富阅历. ...

  8. 2019-08-20 纪中NOIP模拟A组

    T1 [JZOJ6310] Global warming 题目描述 给定整数 n 和 x,以及一个大小为 n 的序列 a. 你可以选择一个区间 [l,r],然后令 a[i]+=d(l<=i< ...

  9. 2019-08-18 纪中NOIP模拟A组

    T1 [JZOJ6309] 完全背包 题目描述

随机推荐

  1. 【小方法】navicate for mysql使数据库可以识别中文

    右键选择新建数据库,将字符集与排序规则改成utf-8形式

  2. css position absolute相对于父元素的设置方式

    手机赚钱怎么赚,给大家推荐一个手机赚钱APP汇总平台:手指乐(http://www.szhile.com/),辛苦搬砖之余用闲余时间动动手指,就可以日赚数百元 大家知道css的position abs ...

  3. MySQL 数据库的提速器-写缓存(Change Buffer)

    写缓存(Change Buffer) 是一种特殊的数据结构,用于在对数据变更时,如果数据所在的数据页没有在 buffer pool 中的话,在不影响数据一致性的前提下,InnoDB 引擎会将对数据的操 ...

  4. Mumbai:1 Vulnhub Walkthrough

    靶机地址: https://www.vulnhub.com/entry/mumbai-1,372/ 主机探测: 主机端口扫描: FTP 下载Note文件 TODO: Move these multip ...

  5. Windows server 2012 出现大量无名已断开连接用户清楚办法

    打开cmd命令窗口,执行  taskkill /f /im winlogon.exe /t

  6. 有关版本控制--SVN

    什么是版本控制? 这个之前有记录过相关的内容 版本管理就是管理更新的历史记录, 它给我们提供了一些在软件开发过程中必不可少的功能,例如: 记录一款软件添加或更改源代码的过程 回滚到特定阶段,恢复误删除 ...

  7. The server cannot be started because one or more of the ports are invalid. Open the server editor and correct the invalid ports.

    在eclipse里运行jsp文件最初迟迟没有反应,重启报了这个错误,tomcat的端口设置有问题.需要打开服务器设置一下端口号. 点击Servers,如果没有这一项,按照Window-Show Vie ...

  8. NB-Iot和GPRS信号通信模式的对比

    NB-Iot和GPRS信号通信模式的对比

  9. Redis-异步消息

    关于异步消息,大家都知道,如下: 这些用起来都是比较复杂的,RabbitMQ先要创建Exchange,在创建Queue,还要将Queue和Exchange通过某种规则绑定起来.发消息之前要指定rout ...

  10. 关于GC(垃圾回收)

    当我用new创建一个对象时,当可分配的内存不足GC就会去回收未使用的对象,但是GC的操作是非常复杂的,会占用很多CPU时间,对于移动设备来说频繁的垃圾回收会严重影响性能.下面的建议可以避免GC频繁操作 ...