[CSP-S模拟测试]:Race(数学+Trie树)

题目描述

一年一度的运动会开始了。有$N$个选手参赛,第$i$个选手有一个能力值(保证$A[i]$两两不同),比赛一共进行了天。在第$j$天($0\leqslant j\leqslant 2^{m-1}$)的比赛中,第$i$个选手的得分为$A[i]\ xor\ j$,然后从大到小排名,排名为$x$($x$从$0$开始)的同学会获得的积分,你需要求出每个同学最后总的积分和$q[i]$模${10}^9+7$的结果$p[i]$。为了避免输出文件过大,你只要输出$p[i]$的异或和即可。


输入格式

第一行两个整数,分别代表$N,M$。
接下来一行$N$个整数,第$i$个数代表$A[i]$。


输出格式

一个整数代表答案。


样例

样例输入:

3 2
0 1 2

样例输出:

8


数据范围与提示

对于$10\%$的数据,$M\leqslant 5$。
对于$30\%$的数据,$N\leqslant 100$。
对于$50\%$的数据,$N\leqslant 1,000$。
对于$100\%$的数据,$N\leqslant 200,000,M\leqslant 30,A[i]<2^m$。


题解

考虑怎么求出$x$的答案。平方相当于是枚举两个人(可以相同),把这两个人同时排在$x$前面的天数计入答案。那么对于$x$,如果我们求出$f[i]$也就是能力值的二进制中第$i+1$到$M-1$位都和他相等且第$i$位不同的人有多少个,那么这些人是否排在他前面只由第$i$位确定,一共有$2^{(M-1)}$天,而且不需要从这些人中枚举两个人了,因为直接平方即可。我们只要枚举$i$和$j$,$f[i]$这些人和$f[j]$这些人同时排在他前面的天数为$2^{(M-2)}$,所以把$2\times f[i]\times f[j]\times 2^{(M-2)}$计入答案。具体实现有很多方法,可以用$trie$树实现。

时间复杂度:$\Theta(N)$。

期望得分:$100$分。

实际得分:$100$分。


代码时刻

#include<bits/stdc++.h>
using namespace std;
int n,m;
int trie[10000000][2],cnt;
long long size[10000000];
long long ans;
void insert(int x)
{
	int p=0;
	for(int i=m-1;i>=0;i--)
	{
		int c=(x>>i)&1;
		if(!trie[p][c])trie[p][c]=++cnt;
		p=trie[p][c];
		size[p]++;
	}
}
void dfs(int x,long long sum,long long num)
{
	if(trie[x][0])dfs(trie[x][0],(sum+(size[trie[x][1]]*size[trie[x][1]]%1000000007*(1<<m-1)%1000000007+size[trie[x][1]]*num%1000000007*(1<<m-1)%1000000007)%1000000007)%1000000007,num+size[trie[x][1]]);
	if(trie[x][1])dfs(trie[x][1],(sum+(size[trie[x][0]]*size[trie[x][0]]%1000000007*(1<<m-1)%1000000007+size[trie[x][0]]*num%1000000007*(1<<m-1)%1000000007)%1000000007)%1000000007,num+size[trie[x][0]]);
	if(!trie[x][0]&&!trie[x][1])ans^=sum;
}
int main()
{
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)
	{
		int a;scanf("%d",&a);
		insert(a);
	}
	dfs(0,0,0);
	printf("%lld",ans);
	return 0;
}


rp++

原文地址:https://www.cnblogs.com/wzc521/p/11566898.html

时间: 2024-11-02 19:58:39

[CSP-S模拟测试]:Race(数学+Trie树)的相关文章

[CSP-S模拟测试]:联盟(搜索+树的直径)

题目描述 $G$国周边的$n$个小国家构成一个联盟以抵御$G$国入侵,为互相支援,他们建立了$n−1$条双向通路,使得任意两个国家可以经过通路相互到达.当一个国家受到攻击时,所有其它国家都会沿着最短路径前往这个国家进行支援,经过每条通路所需的时间均为$1$.定义一个国家的危险程度为所有国家全部赶到需要的最短时间,联盟的危险程度为所有国家的危险程度的最大值.为了降低危险程度,联盟决定断开一条通路并任意连接一条通路,使得危险程度尽可能小,并要求改建完成之后任意两个国家可以经过通路互相到达.他们决定让

[CSP-S模拟测试]:Permutation(线段树+拓扑排序+贪心)

题目描述 你有一个长度为$n$的排列$P$与一个正整数$K$你可以进行如下操作若干次使得排列的字典序尽量小对于两个满足$|i−j|\geqslant K$且$|P_i−P_j|=1$的下标$i$与$j$,交换$P_i$与$P_j$ 输入格式 第一行包括两个正整数$n$与$K$第二行包括$n$个正整数,第$i$个正整数表示$P_i$ 输出格式 输出一个新排列表示答案输出共$n$行,第$i$行表示$P_i$ 样例 样例输入: 8 34 5 7 8 3 1 2 6 样例输出: 12675348 数据范

[CSP-S模拟测试]:d(贪心+树状数组)

题目传送门(内部题65) 输入格式 第一行,一个自然数$T$,代表数据组数.对于每组数据:第一行,一个正整数$n$,一个自然数$m$.接下来$n$行,每行两个正整数,$a_i,b_i$. 输出格式 对于每组数据,输出一行,一个整数,代表答案. 样例 样例输入: 3 2 0 5 10 5 5 2 1 1 1 2 2 3 1 3 5 4 4 5 3 样例输出: 25412 数据范围与提示 保证$0\leqslant m<n,a_i,b_i\leqslant 10^5$. 题解 题目并不难,考虑贪心,

基于 trie 树的最长匹配分词测试

测试一个基于trie树的分词,没有应用任何统计模型,分词的效率估计会很高但是分词准确率很差. reference http://www.hankcs.com/program/java/tire-tree-participle.html https://github.com/ansjsun/tree_split

hdu 4099 Revenge of Fibonacci Trie树与模拟数位加法

Revenge of Fibonacci 题意:给定fibonacci数列的前100000项的前n位(n<=40);问你这是fibonacci数列第几项的前缀?如若不在前100000项范围内,输出-1: 思路:直接使用数组模拟加法,再用Trie树插入查找即可:但是一般使用new Trie()的代码都是MLE的.反而我之前写的,直接得到数组大小的maxnode版本的内存可以接受:并且还有一点就是前40位的精度问题:由于是自己计算出来的finboncci数列,并不是系统给的,所以1的进位不会形成递推

hdu4886 TIANKENG’s restaurant(Ⅱ) (trie树或者模拟进制)

TIANKENG’s restaurant(Ⅱ) Time Limit: 16000/8000 MS (Java/Others)    Memory Limit: 130107/65536 K (Java/Others)Total Submission(s): 456    Accepted Submission(s): 149 Problem Description After improving the marketing strategy, TIANKENG has made a fort

【BZOJ4523】[Cqoi2016]路由表 Trie树模拟

[BZOJ4523][Cqoi2016]路由表 Description 路由表查找是路由器在转发IP报文时的重要环节.通常路由表中的表项由目的地址.掩码.下一跳(Next Hop)地址和其他辅助信息组成.例如: 当路由器收到一个IP报文时,会将报文中的目的IP地址与路由表中的表项逐条进行比较,选择匹配且最明确的表项,将报文转发给该表项中指定的下一跳. 匹配的过程是将报文中的目的地址和表项中的目的地址分别转为二进制串,再查看表项中的掩码长度,若掩码长度为x,则将两个二进制串的前x位进行比较,如果相

机房测试1:big(贪心+Trie树)

题目: 分析: 考虑最暴力的办法:枚举选哪个数,枚举对手在哪个时间变化,然后统计答案. 对于异或这一类问题,考虑区间异或可以抵消重复区间,维护一个前缀异或和:pre[i]表示1~i的异或和,suf[i]表示i~n的异或和. 将对手的式子化简,2*x即将x向左移一位,/( 2^n )为向右移n位,+2*x ,%2^n类似. 模拟一下:12345 -> 123450 -> 123451 -> 23451 每次枚举对手要变的时间i,最后的值即为:work ( pre[i] ^ x ) ^ su

机房测试:race(trie)

题目: 分析: 先不考虑天数的限制,直接对每一个人建一颗trie. 对于每一个人来说,他的x的贡献来源于trie树上所有在他右边的点(都比他大). 将每一个子树所有的叶子结点记为f,x^2=(f1+f2+……fx)^2 将右式拆开看:f i *f i + f i * f j *2(枚举i,j统计贡献,*2是因为 i 和 j 可以交换) 再加上天数的限制:每一个人的A[i]异或上天数 j,相当于trie树的形态发生改变了(01边交换) 对于1来说,又多了一部分贡献,也就是说,对于右子树来说,当且仅