hdu 5419 線段樹 or 差分字首和
阿新 • • 發佈:2019-02-17
題意:有n個禮物,1~n。m個區間,第i個為li~ri。每次隨機三個區間,取走 no less than max(li,lj,lk) and no larger than間的禮物,問取走禮物個數的期望
解法一:線段樹區間更新,對大於三的點C(n,3),後求和。值為n說明有n官網區間可以覆蓋這個點,從中選三個。
程式碼:
解法二:#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #include <vector> #include <queue> #include <stack> #include <set> #include <map> #include <string> #include <cmath> #include <cstdlib> #include <ctime> using namespace std; #define mem(a,b) memset((a),(b),sizeof((a))) #define lson l , m , rt << 1 #define rson m + 1 , r , rt << 1 | 1 #define root 1 , n , 1 #define ll long long void RI (int& x){ x = 0; char c = getchar (); while (c == ' '||c == '\n') c = getchar (); bool flag = 1; if (c == '-'){ flag = 0; c = getchar (); } while (c >= '0' && c <= '9'){ x = x * 10 + c - '0'; c = getchar (); } if (!flag) x = -x; } void RII (int& x, int& y){RI (x), RI (y);} void RIII (int& x, int& y, int& z){RI (x), RI (y), RI (z);} const int maxn = 50010; ll add[maxn<<2]; ll sum[maxn<<2]; void PushUp(int rt) { sum[rt] = sum[rt<<1] + sum[rt<<1|1]; } void PushDown(int rt,int m) { if (add[rt]) { add[rt<<1] += add[rt]; add[rt<<1|1] += add[rt]; sum[rt<<1] += add[rt] * (m - (m >> 1)); sum[rt<<1|1] += add[rt] * (m >> 1); add[rt] = 0; } } void update(int L,int R,int c,int l,int r,int rt) { if (L <= l && r <= R) { add[rt] += c; sum[rt] += (ll)c * (r - l + 1); return ; } PushDown(rt , r - l + 1); int m = (l + r) >> 1; if (L <= m) update(L , R , c , lson); if (m < R) update(L , R , c , rson); PushUp(rt); } ll query(int L,int R,int l,int r,int rt) { if (L <= l && r <= R) { return sum[rt]; } PushDown(rt , r - l + 1); int m = (l + r) >> 1; ll ret = 0; if (L <= m) ret += query(L , R , lson); if (m < R) ret += query(L , R , rson); return ret; } int mon[maxn]; ll gcd(ll a, ll b){ return b==0?a:gcd(b,a%b); } int main() { //freopen("test.txt","r",stdin); int T; RI(T); while(T --){ int n,m; RII(n,m); mem(sum,0);mem(add,0); for(int i = 1;i <= n;i ++){ RI(mon[i]); } for(int i = 0;i < m;i ++){ int l,r; RII(l,r); update(l,r,1,1,n,1); } ll ans = 0; for(int i = 1;i <= n;i ++){ ll nn = query(i,i,1,n,1);//cout<<nn<<' '; if(nn >= 3)ans += (ll)mon[i]*nn*(nn-1)*(nn-2)/6; } if(m <= 2){cout<<0<<endl;continue;} ll mu = (ll)m*(m-1)*(m-2)/6; if(ans == 0){cout<<0<<endl;continue;} ll gg = gcd(ans,mu); ans /= gg;mu /= gg; if(mu == 1){ cout<<ans<<endl; } else printf("%I64d/%I64d\n",ans,mu); } return 0; }
不用線段樹,對於每個區間,起點加一,終點減一。具體見程式碼。
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #include <vector> #include <queue> #include <set> #include <map> #include <string> #include <cmath> #include <cstdlib> #include <ctime> using namespace std; #define mem(a,b) memset((a),(b),sizeof((a))) #define ll long long void RI (int& x){ x = 0; char c = getchar (); while (c == ' '||c == '\n') c = getchar (); bool flag = 1; if (c == '-'){ flag = 0; c = getchar (); } while (c >= '0' && c <= '9'){ x = x * 10 + c - '0'; c = getchar (); } if (!flag) x = -x; } void RII (int& x, int& y){RI (x), RI (y);} void RIII (int& x, int& y, int& z){RI (x), RI (y), RI (z);} const int maxn = 50010; int mon[maxn]; int num[maxn]; int main() { //freopen("test.txt","r",stdin); int T; RI(T); while(T --){ int n,m; RII(n,m); mem(num,0); for(int i = 1;i <= n;i ++){ RI(mon[i]); } for(int i = 0;i < m;i ++){ int l,r; RII(l,r); num[l] ++;num[r+1] --; } ll ans = 0; int tmp = 0; for(int i = 1;i <= n;i ++){ tmp += num[i];//cout<<tmp<<' '; if(tmp >= 3)ans += (ll)mon[i]*tmp*(tmp-1)*(tmp-2)/6; } if(m <= 2){cout<<0<<endl;continue;} ll mu = (ll)m*(m-1)*(m-2)/6; if(ans == 0){cout<<0<<endl;continue;} ll gg = __gcd(ans,mu); ans /= gg;mu /= gg; if(mu == 1){ cout<<ans<<endl; } else printf("%I64d/%I64d\n",ans,mu); } return 0; }