您的位置:首页 > 其它

BZOJ2038: [2009国家集训队]小Z的袜子(hose)

2017-11-03 21:45 218 查看

莫队

题目传送门

莫队板子题。。。至于怎么维护答案,让我们推一推式子:

令t[i]表示上一次询问中颜色为i的袜子数量。

Cmn=n!m!(n−m)!

ans=∑ni=1C2t[i]C2r−l+1

上面=∑ni=1t[i]!2(t[i−2])!=∑ni=1t[i](t[i]−1)2

下面=(r−l+1)!2(r−l−1)!=(r−l+1)(r−l)2

约分展开得

ans=∑ni=1t[i]2−∑ni=1t[i](r−l+1)(r−l)=∑ni=1t[i]2−(r−l+1)(r−l+1)(r−l)

然后我们只要算∑ni=1t[i]就可以啦!

代码:

#include<cmath>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define MAXN 50000
using namespace std;
typedef long long LL;
struct qstn{
int l,r,id,kl,kr;
}que[MAXN+5];
int n,m;
LL sum;
int a[MAXN+5],t[MAXN+5];
LL ans[MAXN+5][2];
inline char readc(){
static char buf[100000],*l=buf,*r=buf;
if (l==r) r=(l=buf)+fread(buf,1,100000,stdin);
if (l==r) return EOF; return *l++;
}
inline int _read(){
int num=0; char ch=readc();
while (ch<'0'||ch>'9') ch=readc();
while (ch>='0'&&ch<='9') { num=num*10+ch-48; ch=readc(); }
return num;
}
bool cmp(qstn x,qstn y){
return (x.kl<y.kl||(x.kl==y.kl&&x.kr<y.kr));//按照块的编号排
}
void nsrt(int l,int r,int v){
for (int i=l;i<=r;i++){//按照那样算过去
sum-=(LL)t[a[i]]*t[a[i]];
t[a[i]]+=v;
sum+=(LL)t[a[i]]*t[a[i]];
}
}
LL gcd(LL a,LL b){
if (b==0) return a;
return gcd(b,a%b);
}
int main(){
n=_read(),m=_read(); int kk=sqrt(n);
for (int i=1;i<=n;i++) a[i]=_read();
for (int i=1;i<=m;i++){
que[i].id=i,que[i].l=_read(),que[i].r=_read();
que[i].kl=(que[i].l-1)/kk+1; que[i].kr=(que[i].r-1)/kk+1;//不分块会死人
}
sort(que+1,que+m+1,cmp);
int l=1,r=0,nd;
for (int i=1;i<=m;i++){
if (que[i].l>l) nsrt(l,que[i].l-1,-1);
else nsrt(que[i].l,l-1,1);
if (que[i].r>r) nsrt(r+1,que[i].r,1);
else nsrt(que[i].r+1,r,-1);
l=que[i].l,r=que[i].r,nd=que[i].id;
ans[nd][0]=sum-(r-l+1);
ans[nd][1]=(LL)(r-l+1)*(r-l);
LL k=gcd(ans[nd][0],ans[nd][1]);
ans[nd][0]/=k; ans[nd][1]/=k;
}
for (int i=1;i<=m;i++)
printf("%lld/%lld\n",ans[i][0],ans[i][1]);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: