BZOJ 2038小z的袜子

来源:互联网 发布:淘宝排名靠前技巧软件 编辑:程序博客网 时间:2024/05/01 16:28

题意:

给一个序列,区间询问选两数相同的概率。

解:

莫队算法

n分块,询问先按左端点在块中位置,再按右端点位置排序,处理时每个询问间暴力转移,可以证明是O(nn)

代码:

#include<cstdio>#include<cstring>#include<cstdlib>#include<algorithm>#include<vector>#include<cmath>#define For(i,j,k) for(int i=(j);i<=(int)k;i++)#define Forr(i,j,k) for(int i=(j);i>=(int)k;i--)#define Set(a,b) memset(a,b,sizeof(a))#define pb push_back#define ll long long #define getchar getchar_unlocked #define Rep(i,u) for(int i=Begin[u],v=to[i];i;i=Next[i],v=to[i])using namespace std;const int N=50010,INF=0x3f3f3f3f;template <class T>inline void read(T &x){    x=0;char c=getchar();int f(0);    while(c<'0'||c>'9')f|=(c=='-'),c=getchar();    while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+(c^48),c=getchar();    x=f?-x:x;}ll gcd(ll a,ll b){return b?gcd(b,a%b):a;}ll ans,f[N];int col[N],n,m,blo,pos[N];struct node{    int l,r,id;    ll a,b;    inline void redc(){        ll k=gcd(a,b);        a/=k,b/=k;    }}a[N];inline bool cmpid(node a,node b){return a.id<b.id;}inline bool cmpb(node a,node b){return pos[a.l]<pos[b.l]||(pos[a.l]==pos[b.l]&&a.r<b.r);}inline void init(){    read(n),read(m);    For(i,1,n)read(col[i]);    blo=(int)sqrt(n+0.5);    For(i,1,n)pos[i]=(i-1)/blo+1;    For(i,1,m)read(a[i].l),read(a[i].r),a[i].id=i;}#define sqr(x) (x)*(x)inline void update(int i,int add){    ans-=sqr(f[col[i]]),f[col[i]]+=add,ans+=sqr(f[col[i]]);}inline void solve(){    sort(a+1,a+m+1,cmpb);    for(int i=0,l=1,r=0,L,R;i<=m;i++){        L=a[i].l,R=a[i].r;        while(r<R)update(r+1,1),r++;        while(r>R)update(r,-1),r--;        while(l<L)update(l,-1),l++;        while(l>L)update(l-1,1),l--;        a[i].a=ans-(R-L+1),a[i].b=(ll)(R-L+1)*(R-L);        if(L==R)a[i].b=1;        a[i].redc();    }    sort(a+1,a+m+1,cmpid);    For(i,1,m)printf("%lld/%lld\n",a[i].a,a[i].b);}int main(){    init();    solve();    return 0;}
0 0
原创粉丝点击