[國家集訓隊]小Z的襪子
阿新 • • 發佈:2018-12-18
題目
思路
設 a,b,c……為每種顏色出現的次數; 答案是:
(a∗(a−1)/2+b∗(b−1)/2+c∗(c−1)/2…)/((R−L+1)∗(R−L)/2)
化簡一下:
(a2+b2+c2+……-(a+b+c+……))/(R-L+1)(R-L)
那麼就是
(a2+b2+c2+……-(R-L+1))/(R-L+1)(R-L)
於是,直接莫隊!
程式碼
#include<cstring> #include<cstdio> #include<cmath> #include<algorithm> #define ll long long using namespace std; const int N=5e4+77,M=5e4+77; struct ahah { ll L,R,p,f; }ask[N]; struct haha { ll x,y; }ans[N]; ll answer,n,m,q,a[N],cnt[N],k; ll gcd(ll a,ll b) { return !b?a:gcd(b,a%b); } bool comp(ahah a,ahah b) { return a.L/k==b.L/k?a.R<b.R:a.L<b.L; } void remove(ll pos) { if(--cnt[a[pos]]>0)answer+=(-2)*(cnt[a[pos]]);} void add(ll pos){ if(++cnt[a[pos]]>1)answer+=2*(cnt[a[pos]]-1); } void work(ll x,ll y,ll p) { if(!x)ans[p].x=0,ans[p].y=1; else { ll k=gcd(x,y); ans[p].x=x/k; ans[p].y=y/k; } } int main() { scanf("%lld%lld",&n,&q); k=sqrt(n); for(int i=1; i<=n; i++)scanf("%lld",&a[i]); for(int i=1; i<=q; i++)scanf("%lld%lld",&ask[i].L,&ask[i].R),ask[i].p=i; sort(ask+1,ask+1+q,comp); ll curl=0,curr=0; for(int i=1; i<=q; i++) { ll L=ask[i].L,R=ask[i].R; if(L==R) { ans[ask[i].p].x=0; ans[ask[i].p].y=1; continue; } while(curl<L)remove(curl++); while(curl>L)add(--curl); while(curr<R)add(++curr); while(curr>R)remove(curr--); work(answer,(R-L+1)*(R-L),ask[i].p); } for(int i=1; i<=q; i++)printf("%lld/%lld\n",ans[i].x,ans[i].y); }