11.1 T3.race(Trie+x^2的转化)

来源:互联网 发布:淘宝用户服务协议 编辑:程序博客网 时间:2024/06/06 13:07

题目描述
一年一度的运动会开始了. 有N个选手参赛, 第i个选手有一个能力值Ai, 比赛一共进行了 2^M天. 在第j天(0⩽ j⩽2^M−1 )的比赛中, 第i个选手的得分为A[i] xor j, 然后从大到小排名, 排名为x(x从0开始)的同学会获得 x^2的积分, 你需要求出每个同学最后总的积分和q[i]模 1e9+7 的结果p[i].
为了避免输出文件过大, 你只要输出p[i]的异或和即可.

输入格式
第一行三个整数, 分别代表N, M.
接下来一行N个整数, 第i个数代表A[i].
输出格式
一个整数代表答案.

样例
race.in
3 2
0 1 2
race.out
8

数据范围
对于10%的数据, M <= 5.
对于30%的数据, N <= 100.
对于50%的数据, N <= 1000.
对于100%的数据, N <= 200000, M <= 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*f[i]*f[j]*2^(M-2)计入答案. 具体实现有很多方法, 可以用trie树实现.

在看std的时候看到这样一句:assert(0);

定义

assert宏的原型定义在

#include <assert.h>void assert( int expression );

assert的作用是现计算表达式 expression ,如果其值为假(即为0),那么它先向stderr打印一条出错信息,然后通过调用 abort 来终止程序运行。

//这里写std#include<cstdio>#include<cstring>#include<iostream>#include<algorithm>#include<map>#define ll long longusing namespace std;const int N=200003;const int mod=1000000007;int n,m,A,ch[N*30][2],tot=0,sz[N*30];ll ans=0;void insert(int A){    int now=0;    for (int i=m-1;i>=0;i--)    {        int x=(A>>i)&1;        if (!ch[now][x]) ch[now][x]=++tot;        now=ch[now][x];        sz[now]++;                 //每个节点上的子串个数     }}void dfs(int x,ll sum,ll num){    ll tmp,size;    size=sz[ch[x][1]],tmp=0;    tmp=size*size%mod*(1<<m-1)%mod;    tmp=(tmp+size*num%mod*(1<<m-1)%mod)%mod;    if (ch[x][0]) dfs(ch[x][0],(sum+tmp)%mod,num+size);    size=sz[ch[x][0]],tmp=0;    tmp=size*size%mod*(1<<m-1)%mod;    tmp=(tmp+size*num%mod*(1<<m-1)%mod)%mod;    if (ch[x][1]) dfs(ch[x][1],(sum+tmp)%mod,num+size);    if (!ch[x][0]&&!ch[x][1]) ans^=sum;}map<int,bool> vis;int main(){    freopen("race.in","r",stdin);      freopen("race.out","w",stdout);    scanf("%d%d",&n,&m);    for (int i=1;i<=n;i++)     {        scanf("%d",&A);        insert(A);        if (vis.count(A)) return 0;        vis[A]=1;    }    dfs(0,0,0);    printf("%lld",ans);    return 0; }