Codeforces Round #361 (Div. 2)

来源:互联网 发布:高通编译linux 编辑:程序博客网 时间:2024/05/15 02:06

C. Mike and Chocolate Thieves

  二分搜。

#include <bits/stdc++.h>using namespace std;#define ll long longll a[200000+10];int main(){    for(ll i = 2;i<=200000;i++){        a[i] = i*i*i;    }    ll r = 1e16;    ll l = 8;    ll m;    cin>>m;    bool ok = 0;    ll ans = 1e18;    while(l<=r){        ll mid = (l+r)>>1;        ll val = 0;        ll End=min(200000LL,mid);        for(ll i=2;i<=End;i++){            val += mid/a[i];        }        if(val<m){            l=mid+1;        }else if(val>m){            r=mid-1;        }else{            r=mid-1;            ok = 1;            ans = min(ans,mid);        }    }    if(ok){        cout<<ans<<endl;    }else{        cout<<-1<<endl;    }    return 0;}

D. Friends and Subsequences

  ST求静态区间最值。然后枚举起点,二分搜或者直接拿ST推出。

#include <bits/stdc++.h>using namespace std;#define ll long longconst int maxn = 200010;const int INF = 2e9;int a[maxn][20];int b[maxn][20];int n;int getMin(int s,int t){    int lg = log2(t-s+1);    int len = 1<<lg;    if(t == s+len-1){        return b[s][lg];    }    return min(b[s][lg],b[t-len+1][lg]);}int getMax(int s,int t){    int lg = log2(t-s+1);    int len = 1<<lg;    if(t == s+len-1){        return a[s][lg];    }    return max(a[s][lg],a[t-len+1][lg]);}int bs1(int s){    int l = s;    int r = n;    int ans = -1;    while(l <= r){        int mid = (l+r)>>1;        int MIN = getMin(s,mid);        int MAX = getMax(s,mid);        if(MIN > MAX){            l = mid + 1;        }else{            r = mid - 1;            if(MIN == MAX){                ans = mid;            }        }    }    return ans;}int bs2(int s){    int l = s;    int r = n;    int ans = -1;    while(l <= r){        int mid = (l+r)>>1;        int MIN = getMin(s,mid);        int MAX = getMax(s,mid);        if(MIN >= MAX){            l = mid + 1;            if(MIN == MAX){                ans = mid;            }        }else{            r = mid - 1;        }    }    return ans;}int main(){    cin>>n;    for(int i=1;i<=n;i++){        scanf("%d",&a[i][0]);    }    for(int i=1;i<=n;i++){        scanf("%d",&b[i][0]);    }    int len = 1;    for(int k=1;k<=19;k++){        for(int i=1;i+len<=n;i++){            a[i][k] = max(a[i][k-1],a[i+len][k-1]);            b[i][k] = min(b[i][k-1],b[i+len][k-1]);        }        len <<= 1;    }    ll ans = 0;    for(int i=1;i<=n;i++){        if(a[i][0]<=b[i][0]){            int s = bs1(i);            int t = bs2(i);            if(~s)ans += (t-s+1);        }    }    cout<<ans<<endl;    return 0;}

E. Mike and Geometry Problem

  先对左端点排序,然后枚举每个区间,作为左端点最大的区间(它们的交集的左端点肯定是这个区间的左端点),然后用组合数计算一下有多少种选法,注意去掉前面出现的右端点过小的区间,得到一个左端点的和。用同样的方法得到右端点的和,相减即可。

#include <bits/stdc++.h>using namespace std;#define ll long longconst ll mod = 1000000007;ll inv[200010]; ll fab[200010];    ll Pow(ll a,int n){      ll re=1;      while(n){          if(n&1){              re*=a;              re%=mod;          }          a*=a;          a%=mod;          n>>=1;      }      return re;  }  ll C(int n,int k){    if(n<k){        return 0;    }    ll res=fab[n]*inv[k];        res%=mod;        res*=inv[n-k];        res%=mod;        return res;    }    struct Seg{    int l,r;    Seg(int l=0,int r=0):l(l),r(r){    }    bool operator<(const Seg &o)const{        return l<o.l;    }}segs[200010];bool cmpR(Seg &a,Seg &b){    return a.r>b.r;}int main(){    fab[0]=1;        for(int i=1;i<=200000;i++){            fab[i]=fab[i-1]*i;            fab[i]%=mod;        }     inv[0]=1;     for(int i=1;i<=200000;i++){        inv[i]=Pow(fab[i],mod-2);      }      int n,k;    cin>>n>>k;    for(int i=1;i<=n;i++){        scanf("%d %d",&segs[i].l,&segs[i].r);        segs[i].r++;    }    sort(segs+1,segs+n+1);    priority_queue<int,vector<int>,greater<int>> pq;    ll lsum = 0;    for(int i=1;i<=n;i++){        while(pq.size() && pq.top()<=segs[i].l){            pq.pop();        }        ll nn = pq.size();        lsum += segs[i].l * C(nn,k-1);        lsum %= mod;        pq.push(segs[i].r);    }    sort(segs+1,segs+n+1,cmpR);    priority_queue<int> pq2;    ll rsum = 0;    for(int i=1;i<=n;i++){        while(pq2.size() && pq2.top()>=segs[i].r){            pq2.pop();        }        ll nn = pq2.size();        rsum += segs[i].r * C(nn,k-1);        rsum %= mod;        pq2.push(segs[i].l);    }    cout<<(rsum-lsum + mod*10)%mod<<endl;    return 0;}
0 0