[随机算法+Hash] Codeforces 799F Round #413 F. Beautiful fountains rows

来源:互联网 发布:知乎老人吸烟猝死案 编辑:程序博客网 时间:2024/06/05 01:28

题目梗概

n个不同的数字,每个数字只出现在[L,R]中。
求所有满足要求的区间的长度和。
要求:出现在该区间的所有数字的个数必须为奇数,且必须有数字存在。

解题思路

考虑一个区间如何才能满足要求。
将每个数字赋上一个(2631,0]的随机值。
这个区间所有数字的异或值再异或上这个区间出现过的数字,如果等于0,那么这个区间满足要求。

对于区间所有数字的异或值构造前缀异或和数组P[]即可。
考虑[L,R]区间出现过的数字的异或值。

一个数字i[L,R]出现过必须满足

!(y[i]<L||x[i]>R)=(y[i]>=Landx[i]<=R)
,满足条件的所有数字就是满足x[i]<=R的数字XOR满足(y[i]<Landx[i]<=R)的数字。

观察(y[i]<Landx[i]<=R),发现如果前一项满足后一项显然也满足,所以这个条件变为y[i]<L

我们分别开数组s[],t[]分别构造满足x[i]<=Ry[i]<L的异或和,数组的构造显然是线性的。
通过以上变换题目初始条件变为满足P[R]^P[L1]==s[R]^t[L]
移项得t[L]^P[L1]==s[R]^P[R]

把前项压进一个map里就可以了。

Ps:本人脸丑,不得不双hash。

#include<map>#include<vector>#include<cstdio>#include<algorithm>#define LL long longusing namespace std;typedef pair<LL,LL> jz;const int maxn=200005;int n,m;inline int _read(){    int num=0;char ch=getchar();    while (ch<'0'||ch>'9') ch=getchar();    while (ch>='0'&&ch<='9') num=num*10+ch-48,ch=getchar();    return num;}map<jz,LL> G,S;vector<int> L[maxn],R[maxn];LL a[maxn],b[maxn],p1[maxn],p2[maxn],ans;int x[maxn],y[maxn],num[maxn];LL calc(LL x){return (x+1)*x*(x+1)/2-x*(x+1)*(2*x+1)/6;}int main(){    n=_read();m=_read();    for (int i=1;i<=n;i++){        x[i]=_read(),y[i]=_read();        L[x[i]].push_back(i);R[y[i]].push_back(i);        a[i]=(LL)rand()*rand()*rand()*rand();        b[i]=(LL)rand()*rand()*rand()*rand();        p1[x[i]]^=a[i];p1[y[i]+1]^=a[i];        p2[x[i]]^=b[i];p2[y[i]+1]^=b[i];        num[x[i]]++;num[y[i]+1]--;    }    for (int k=0;k<2;k++) for (int i=1;i<=m;i++) p1[i]^=p1[i-1],p2[i]^=p2[i-1];    G[jz(0,0)]=1;    LL s1=0,s2=0,t1=0,t2=0;    for (int i=1;i<=m;i++){        for (int j=0;j<L[i].size();j++) s1^=a[L[i][j]],s2^=b[L[i][j]];        ans+=G[jz(s1^p1[i],s2^p2[i])]*i-S[jz(s1^p1[i],s2^p2[i])];        for (int j=0;j<R[i].size();j++) t1^=a[R[i][j]],t2^=b[R[i][j]];        G[jz(t1^p1[i],t2^p2[i])]++;S[jz(t1^p1[i],t2^p2[i])]+=i;    }    for (int i=1;i<=m;i++) num[i]+=num[i-1];    int i=1,j;    while(i<=m){        j=i;        while(j<=m&&num[j]==0) j++;        ans-=calc(j-i);i=j+1;    }    printf("%lld\n",ans);    return 0;}
原创粉丝点击