[luogu1494] [國家集訓隊]小Z的襪子
阿新 • • 發佈:2018-12-02
直接普通莫隊敲上去。問題在於每隻襪子對於答案的貢獻。1只襪子的恭喜是0,2只是1,3只是3……其實就是x的貢獻是\(1+2+3+...+(x-1)\),這裡直接等差數列求和就行了。
最後求出gcd,就可以得到最簡分式
#include <cstdio> #include <cstring> #include <algorithm> #include <cmath> #define MAXN 50005 struct Node { int l,r,num; long long ans; }G[MAXN]; int book[MAXN]; int cur[MAXN],rec[MAXN]; int N,M,size; long long ans = 0; long long gcd(long long a,long long b) { return b?gcd(b,a%b):a; } inline long long calc(long long x) { if(x<=0) return 0; return x&1 ? ((x>>1)+1)*x : (x>>1)*(x|1); } inline bool cmp(Node a,Node b) { return (a.l/size)^(b.l/size) ? a.l<b.l : ( (a.l/size)&1 ? a.r<b.r : a.r>b.r); } inline void work(int x,int u) { ans -= calc(book[cur[x]]-1); book[cur[x]] += u; ans += calc(book[cur[x]]-1); } int main() { scanf("%d%d",&N,&M); for(int i=1;i<=N;++i) { scanf("%d",&cur[i]); } for(int i=1;i<=M;++i) { scanf("%d%d",&G[i].l,&G[i].r); G[i].num = i; } size = sqrt(N); std::sort(G+1,G+1+M,cmp); std::memset(book,0,sizeof(book)); ans = 0; int L = G[1].l,R = G[1].r; for(int i=L;i<=R;++i) work(i,1); for(int i=1;i<=M;++i) { while(L>G[i].l) work(--L,1); while(R>G[i].r) work(R--,-1); while(R<G[i].r) work(++R,1); while(L<G[i].l) work(L++,-1); rec[G[i].num] = i; G[i].ans = ans; } for(int i=1;i<=M;++i) { long long num = G[rec[i]].r - G[rec[i]].l + 1; num = (num*(num-1))>>1; if(G[rec[i]].l==G[rec[i]].r) num = 1; long long temp = gcd(G[rec[i]].ans,num); printf("%lld/%lld\n",G[rec[i]].ans/temp,num/temp); } return 0; }