您的位置:首页 > 大数据 > 人工智能

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

2017-08-01 23:19 597 查看

题目梗概

有n个不同的数字,每个数字只出现在[L,R]中。

求所有满足要求的区间的长度和。

要求:出现在该区间的所有数字的个数必须为奇数,且必须有数字存在。

解题思路

考虑一个区间如何才能满足要求。

将每个数字赋上一个(263−1,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]<=R,y[i]<L的异或和,数组的构造显然是线性的。

通过以上变换题目初始条件变为满足P[R]^P[L−1]==s[R]^t[L]

移项得t[L]^P[L−1]==s[R]^P[R]

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

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

#include<map>
#include<vector>
#include<cstdio>
#include<algorithm>
#define LL long long
using 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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: