[计数 补集转换][阈值] Codechef SEAARC.Sereja and Arcs
来源:互联网 发布:淘宝女装背景 编辑:程序博客网 时间:2024/06/04 00:27
传送门
%%%度神
很强的计数题
题目就是求形如ABAB的个数,发现这个很难求,补集转换一下,答案就是总数减去AABB和ABBA的个数
求总数很简单,就是
AABB的个数可以枚举p,然后用颜色的前后缀和求出来。
重点就是求ABBA了
直接求还是不好求,可以设一个阈值
那么就有四种情况:
A∈Big,B∈Big A∈Big,B∈Small A∈Small,B∈Big A∈Small,B∈Small
分类讨论
A∈Small,B∈Small 这个子问题是小颜色包含小颜色,这个子问题就是典型的二维数点,可以证明
∏i∈X(ai2) 是O(nS) 级别的,也就是这些颜色的数对和在nS 以内,那么就用离线的求二维数点的方案就可以了。复杂度加个树状数组的log ,就是O(nSlogn) A∈Big,B∈Small
大颜色包含小颜色,枚举每种小颜色x 和大颜色y ,枚举左端点,右端点可以求出答案∑i=2ax∑j=1i−1prey,j×(ay−prey,i) 维护一下∑i=2ax(ay−prey,i)∑j=1i−1prey,j ∑i−1j=1prey,j ,就不需要枚举右端点了,整个复杂度就是O(n2S) A∈Small,B∈Big 和A∈Small,B∈Big
这两类情况的解法一样,枚举A的左端点和右端点,枚举B的种类,答案是展开可以得到∑i=2aA∑j=1i−1(preB,i−preB,j2) 同样维护12∑i=2aA(pre2B,i×(i−1)−2×preB,i∑j=1i−1preB,j+∑j=1i−1pre2B,j+∑j=1i−1preB,j+preB,i×(i−1)) ∑i−1j=1preB,j ,∑i−1j=1pre2B,j 就可以不用枚举右端点,复杂度就是O(n2S)
这样就可以了理论上
打了一个晚上结果不小心关了电脑,代码就不见了…
第二天10分钟又打了一遍…
#include <cstdio>#include <iostream>#include <algorithm>#include <cmath>#include <vector>#include <cstring>#include <string>using namespace std;const int N=100010,M=330,P=1e9+7,inv2=P+1>>1;inline char nc(){ static char buf[100000],*p1=buf,*p2=buf; return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;}inline void rea(int &x){ char c=nc(); x=0; for(;c>'9'||c<'0';c=nc());for(;c>='0'&&c<='9';x=x*10+c-'0',c=nc());}inline void add(int &x,int y){ if((x+=y)>=P) x-=P;}int n,S,ans,a[N],pre[N],lst[N],Size[N],bit[N];int pr[M][N],p[N][M],q[N][M],p2[N][M];vector<int> c[N],bg;inline int C(int x){ return 1LL*x*(x-1)/2%P;}inline int Query(int l,int r){ int ret=0; for(;l<=n;l+=l&-l) ret+=bit[l]; for(r++;r<=n;r+=r&-r) ret-=bit[r]; return ret;}inline void Add(int x){ for(;x;x-=x&-x) bit[x]++;}int main(){ freopen("arcs.in","r",stdin); freopen("arcs.out","w",stdout); rea(n); S=sqrt(n); for(int i=1;i<=n;i++) rea(a[i]),c[a[i]].push_back(i); for(int i=1;i<=n;i++) pre[i]=lst[a[i]],lst[a[i]]=i; int cur=0; for(int i=1;i<=100000;i++){ if(c[i].size()>S) bg.push_back(i); add(ans,1LL*cur*C(c[i].size())%P),add(cur,C(c[i].size())); } for(int i=1;i<=n;i++){ add(cur,(P-(c[a[i]].size()-Size[a[i]]-1))%P); add(ans,P-1LL*Size[a[i]]*(cur+P-C(c[a[i]].size()-Size[a[i]]-1))%P); Size[a[i]]++; } memset(Size,0,sizeof(Size)); for(int i=1;i<=n;i++){ for(int j=0;j<bg.size();j++) pr[j][i]=pr[j][i-1]+(a[i]==bg[j]); } for(int i=1;i<=n;i++){ if(c[a[i]].size()<=S){ for(int j=0;c[a[i]][j]<i;j++) add(ans,(P-Query(c[a[i]][j]+1,i)+C(Size[a[i]]-j-1))%P),Add(c[a[i]][j]); for(int j=0;j<bg.size();j++){ if(bg[j]==a[i]) continue; q[i][j]=(q[pre[i]][j]+pr[j][pre[i]])%P; add(ans,P-1LL*(c[bg[j]].size()-Size[bg[j]])*q[i][j]%P); } } for(int j=0;j<bg.size();j++){ if(bg[j]==a[i]) continue; p[i][j]=(p[pre[i]][j]+pr[j][pre[i]])%P; p2[i][j]=(1LL*pr[j][pre[i]]*pr[j][pre[i]]+p2[pre[i]][j])%P; add(ans,P-1LL*inv2*((1LL*Size[a[i]]*pr[j][i]%P*pr[j][i]%P+P-2LL*pr[j][i]*p[i][j]%P+p2[i][j]+p[i][j]+P-1LL*Size[a[i]]*pr[j][i]%P)%P)%P); } Size[a[i]]++; } printf("%d\n",ans); return 0;}
阅读全文
0 0
- [计数 补集转换][阈值] Codechef SEAARC.Sereja and Arcs
- Codechef June Challenge 2014 #Sereja and Arcs -- 容斥 + 阈值 + 树状数组
- CODECHEF Sereja and Commands
- 【codechef】Sereja and Votes(模拟)
- CodeChef:Sereja and Tree 2(树形dp)
- Timing Arcs and Unateness
- CodeChef补题计划
- CodeForces Round #223 div.1 D.Sereja and Cinema(组合计数)
- B. Sereja and Array
- Sereja and Bottles
- Sereja and Bottles
- A. Sereja and Bottles
- B. Sereja and Suffixes
- CF380A Sereja and Prefixes
- A. Sereja and Dima
- Sereja and Stairs
- B. Sereja and Stairs
- Sereja and Stairs
- 线代 [矩阵]
- SpringMVCDemo-登录小例子
- 监听器、过滤器、拦截器、servlet的区别
- JDBC工具类
- 守望者的逃离
- [计数 补集转换][阈值] Codechef SEAARC.Sereja and Arcs
- 九度1183:守形数
- Base64编码原理解析与Java实现
- C++(3): C++ 动态内存
- 促销活动表结果的学习探讨
- JetBrains全系列破解
- windows客户端性能测试之内存泄露检查工具umdh.exe
- Windows10+Python3.6下安装NumPy+SciPy+Matplotlib
- Docker 学习总结——云端基于Docker的微服务与持续交付实践