XJOI-NOIP2015提高组模拟题1 day1

其实这只是一道题的题解= =;

博主太弱不会T1T3;

然而我还是要吐槽一下,T2难道你们就没有一点写数据结构的心情吗!

T1:

留坑(不太可能填);

T2:

题意:

给出大小为n的一个四维点集,和m次询问;

每次询问给出一个点,求四维坐标均小于等于这个点的集合大小;

n,m<=30000;

题解:

看到这题的第一反应是排序乱搞,noip难度应该随便玩玩就过了嘛(笑);

但是仔细看看不是这么回事!

bzoj有一道题叫陌上花开——然而那个是三维的;

回忆一下,PoPoQQQ让我们搞排序+CDQ分治+树状数组;

hzwer让我们搞排序+树状数组套平衡树;

反正都是降维,综合一下,就是排序+CDQ分治+树状数组套平衡树不就搞出来了!

码!

具体搞法和一般的CDQ分治差不多,只是插入查询树状数组改成了树状数组套平衡树;

每次插入查询都是时间是O(log^2n)的,总体算上CDQ分治;

时间复杂度O(nlog^3n),空间复杂度O(nlogn);

这个效率还是不错的,但是正解并不是这个;

正解是用bitset来维护集合的交;

每次关于一维排序,求每个询问在这一维上小于等于的点集,用一个bitset记录;

然后将这些bitset与(&)起来,得到的集合就是最后的点集;

复杂度O(4*n^2/32),效率比上面的高级数据结构快一些,并且极为好写;

正解的做法还可以再向高维拓展,而高级数据结构就很难继续了;

(正解代码懒得写了,大家理解一下应该都是可以yy的(笑));

代码:

排序+CDQ分治+树状数组套平衡树:

#include<stdio.h>
#include<string.h>
#include<algorithm>
#define N 31000
#define lson tr[tr[x].l]
#define rson tr[tr[x].r]
using namespace std;
struct node
{
	double a, b, c, d;
	int num_ans, no;
}t[N << 1], temp[N << 1];
struct treap
{
	double val;
	int size, rnd, l, r;
	void clear()
	{
		size = 1, rnd = rand(), l = 0, r = 0;
	}
}tr[N * 20];
double dis[N << 1];
int len, cnt, ans[N];
int root[N << 1];
bool cmp1(node a, node b)
{
	if (a.a == b.a)
		return a.num_ans<b.num_ans;
	return a.a < b.a;
}
bool cmp2(node a, node b)
{
	return a.b < b.b;
}
int lowbit(int x)
{
	return x&(-x);
}
void Pushup(int x)
{
	tr[x].size = lson.size + rson.size + 1;
}
void lturn(int &x)
{
	int t = tr[x].r;
	tr[x].r = tr[t].l;
	tr[t].l = x;
	tr[t].size = tr[x].size;
	Pushup(x);
	x = t;
}
void rturn(int &x)
{
	int t = tr[x].l;
	tr[x].l = tr[t].r;
	tr[t].r = x;
	tr[t].size = tr[x].size;
	Pushup(x);
	x = t;
}
void Insert(int &x, double val)
{
	if (!x)
	{
		tr[x = ++cnt].clear();
		tr[x].val = val;
		return;
	}
	tr[x].size++;
	if (val <= tr[x].val)
	{
		Insert(tr[x].l, val);
		if (tr[x].rnd < lson.rnd)
			rturn(x);
	}
	else
	{
		Insert(tr[x].r, val);
		if (tr[x].rnd > rson.rnd)
			lturn(x);
	}
}
int query(int x, double val)
{
	if (!x)	return 0;
	if (tr[x].val > val)
		return query(tr[x].l, val);
	else
		return lson.size + 1 + query(tr[x].r, val);
}
void add(int k, double val)
{
	while (k <= len)
	{
		Insert(root[k], val);
		k += lowbit(k);
	}
}
void clear(int k)
{
	while (k <= len && root[k])
	{
		root[k] = 0;
		k += lowbit(k);
	}
}
int getans(int k, double val)
{
	int ret = 0;
	while (k)
	{
		ret += query(root[k], val);
		k -= lowbit(k);
	}
	return ret;
}
void divide(int l, int r)
{
	int mid = l + r >> 1;
	memcpy(temp + l, t + l, sizeof(node)*(r - l + 1));
	for (int i = l, j = l, k = mid + 1; i <= r; i++)
	{
		if (temp[i].no <= mid)
			t[j++] = temp[i];
		else
			t[k++] = temp[i];
	}
}
void merge(int l, int r)
{
	int mid = l + r >> 1;
	memcpy(temp + l, t + l, sizeof(node)*(r - l + 1));
	for (int i = l, j = l, k = mid + 1; i <= r; i++)
	{
		if (j <= mid&&k <= r)
			t[i] = temp[j].b < temp[k].b ? temp[j++] : temp[k++];
		else
			t[i] = (j == mid + 1 ? temp[k++] : temp[j++]);
	}
}
void slove(int l, int r)
{
	if (l == r)		return;
	divide(l, r);
	int mid = l + r >> 1, i, j;
	slove(l, mid);
	for (i = mid + 1, j = l, cnt = 0; i <= r; i++)
	{
		while (j <= mid&&t[j].b <= t[i].b)
		{
			if (!t[j].num_ans)
			{
				add(lower_bound(dis + 1, dis + len + 1, t[j].c) - dis, t[j].d);
			}
			j++;
		}
		if (t[i].num_ans)
		{
			ans[t[i].num_ans] += getans(lower_bound(dis + 1, dis + len + 1, t[i].c) - dis, t[i].d);
		}
	}
	while (j >= l)
	{
		if (!t[j].num_ans)
		{
			clear(lower_bound(dis + 1, dis + len + 1, t[j].c) - dis);
		}
		j--;
	}
	slove(mid + 1, r);
	merge(l, r);
}
int main()
{
	int n, m, i, j, k;
	scanf("%d", &n);
	for (i = 1; i <= n; i++)
	{
		scanf("%lf%lf%lf%lf", &t[i].a, &t[i].b, &t[i].c, &t[i].d);
	}
	scanf("%d", &m);
	for (i = 1; i <= m; i++)
	{
		scanf("%lf%lf%lf%lf", &t[i + n].a, &t[i + n].b, &t[i + n].c, &t[i + n].d);
		t[i + n].num_ans = i;
		dis[i + n] = t[i + n].c;
	}
	sort(dis + 1, dis + n + m + 1);
	len = unique(dis + 1, dis + n + m + 1) - dis - 1;
	sort(t + 1, t + n + m + 1, cmp1);
	for (i = 1; i <= n + m; i++)
	{
		t[i].no = i;
	}
	sort(t + 1, t + n + m + 1, cmp2);
	slove(1, n + m);
	for (i = 1; i <= m; i++)
	{
		printf("%d\n", ans[i]);
	}
	return 0;
}

T3:

我选择弃疗,计算几何目前还是弱鸡,等学了半平面交有心情再搞搞(?)吧

时间: 2024-08-24 04:38:11

XJOI-NOIP2015提高组模拟题1 day1的相关文章

XJOI2016提高组模拟题一 排队

就是这样一道题了. 维护这一棵树. 对于第一种操作,我们从题意可知,节点的访问顺序就是DFS序,至于先小后大的限制,只需要用伟大的STL-sort来逐层排序就很好了,代码简洁,时间复杂度低. 按DFS序把这些点存入优先队列,如果该点没人,就在该队列中,人的流动先后顺序就可以用出入优先队列来维护. 对于第二种操作.这里用到了倍增的思想寻找第一个有人的祖宗点,那么这个点下次就要优先进人,所以进队. #include<cstdio> #include<cstdlib> #include&

Noip2015 提高组 Day1

T1神奇的幻方 题目描述 幻方是一种很神奇的N*N矩阵:它由数字1,2,3,……,N*N构成,且每行.每列及两条对角线上的数字之和都相同. 当N为奇数时,我们可以通过以下方法构建一个幻方: 首先将1写在第一行的中间. 之后,按如下方式从小到大依次填写每个数K(K=2,3,…,N*N): 1.若(K−1)在第一行但不在最后一列,则将K填在最后一行,(K−1)所在列的右一列: 2.若(K−1)在最后一列但不在第一行,则将K填在第一列,(K−1)所在行的上一行: 3.若(K−1)在第一行最后一列,则将

刷题总结——子串(NOIP2015提高组)

题目: 题目背景 NOIP2015 提高组 Day2 T2 题目描述 有两个仅包含小写英文字母的字符串 A 和 B .现在要从字符串 A 中取出 k 个互不重叠的非空子串,然后把这 k 个子串按照其在字符串 A 中出现的顺序依次连接起来得到一个新的字符串,请问有多少种方案可以使得这个新串与字符串 B 相等?注意:子串取出的位置不同也认为是不同的方案. 输入格式 第一行是三个正整数 n,m,k,分别表示字符串 A 的长度,字符串 B 的长度,以及问题描述中所提到的 k ,每两个整数之间用一个空格隔

XJOI 郎思轲模拟题

今天比赛的是郎思轲出的模拟题,比较偏数学. 全国青少年奥林匹克联赛 CCF-NOIP 2017模拟试题 提高组(复赛)day1 竞赛时间:210分钟 命题:郎思轲 题目一览: 题目名称 不定长数组 台球游戏 对称的多项式 题目类型 传统型 传统型 传统型 目录 vector billiards poly 可执行文件名 vector billiards poly 输入文件名 vector.in billiards.in poly.in 输出文件名 vector.out billiards.out

[NOIP2015] 提高组 洛谷P2615 神奇的幻方

题目描述 幻方是一种很神奇的N*N矩阵:它由数字1,2,3,……,N*N构成,且每行.每列及两条对角线上的数字之和都相同. 当N为奇数时,我们可以通过以下方法构建一个幻方: 首先将1写在第一行的中间. 之后,按如下方式从小到大依次填写每个数K(K=2,3,…,N*N): 1.若(K−1)在第一行但不在最后一列,则将K填在最后一行,(K−1)所在列的右一列: 2.若(K−1)在最后一列但不在第一行,则将K填在第一列,(K−1)所在行的上一行: 3.若(K−1)在第一行最后一列,则将K填在(K−1)

洛谷-神奇的幻方-NOIP2015提高组复赛

题目描述 幻方是一种很神奇的N*N矩阵:它由数字1,2,3,……,N*N构成,且每行.每列及两条对角线上的数字之和都相同. 当N为奇数时,我们可以通过以下方法构建一个幻方: 首先将1写在第一行的中间. 之后,按如下方式从小到大依次填写每个数K(K=2,3,…,N*N): 1.若(K−1)在第一行但不在最后一列,则将K填在最后一行,(K−1)所在列的右一列: 2.若(K−1)在最后一列但不在第一行,则将K填在第一列,(K−1)所在行的上一行: 3.若(K−1)在第一行最后一列,则将K填在(K−1)

ZROI提高组模拟赛05总结

ZROI提高组模拟赛05总结 感觉是目前为止最简单的模拟赛了吧 但是依旧不尽人意... T1 有一半的人在30min前就A掉了 而我花了1h11min 就是一个简单的背包,我硬是转化了模型想了好久,生生把一个弱智题变成了一个不可做题 最后竟然在转化两次后的模型上以为自己做出来了 这个题比别人多花的1h左右的时间,而且只得到了30分,成为了这场比赛失败的关键因素 T2 依旧是一道简单题 有人20min之内就A掉了 感觉放在CF里最多算一道Div2 D,还是简单的那种 可是我又一次想复杂了 大意就是

提高组模拟赛总结(1)

T1 : 题意:给定一个连续的颜色序列,至多可以去掉k种颜色,问能得到的最大连续单个颜色长度是多少 n <= 10 ^ 5 做法:考试的时候十分斯波,在统计的时候写了线段树统计,实际上根本不用 维护了两个指针表示当前的序列,离散化后用桶维护每一个颜色的数量,如果颜色 <= k + 1就一直加颜色进来,不然就一直移动左指针删除颜色,每次改变某一颜色数量时更新一下最大值就好了 T2: 题意:(实在没办法总结一句话题意了ORZ,总之是个变种的Lis)有 n 个节目,其描述了在 Ti时 刻 Xi号社团

数学方法模拟(洛谷1017 进制转换NOIp2000提高组第一题)

我们可以用这样的方式来表示一个十进制数: 将每个阿拉伯数字乘以一个以该数字所处位置的(值减1)为指数,以10为底数的幂之和的形式.例如:123可表示为 1*10^2+2*10^1+3*10^0这样的形式. 与之相似的,对二进制数来说,也可表示成每个二进制数码乘以一个以该数字所处位置的(值-1)为指数,以2为底数的幂之和的形式.一般说来,任何一个正整数R或一个负整数-R都可以被选来作为一个数制系统的基数.如果是以R或-R为基数,则需要用到的数码为 0,1,....R-1.例如,当R=7时,所需用到