Codeforces Round #361 (Div. 2) 题解 粗鲁地二分 组合数学提炼模型

来源:互联网 发布:bsb的网络意思是什么 编辑:程序博客网 时间:2024/06/06 20:51

题面

A 水

B 一条直线上的点之间钻来钻去,优先队列BFS,穷人版最短路

C m在10的15次方,涉及到k的3次方,小范围打表找规律,发现结果n约等于6倍m,确定n的范围在8*10的15次方以内,二分n是20的时间复杂度,check函数是2*10的5次方时间复杂度。

#include <iostream>#include <cstdio>using namespace std;typedef unsigned long long LL;int main(){    //freopen("data.out", "w", stdout);    LL l = 1, r = 8000000000000000LL, mid, m, ans = 0;    cin>> m;    while(l <= r){        LL sum = 0;        mid = l + (r-l)/2;        for(LL i = 2; i <= 200000; i++){            LL i3 = i*i*i;            if (i3 > mid) break;            sum += mid / i3;        }        if (sum == m){            ans = mid;            r = mid - 1;        }        else if (sum > m){            r = mid - 1;        }        else{            l = mid + 1;        }    }    if (ans > 0)        cout<<ans<<endl;    else        cout<<-1<<endl;    return 0;}


D 好题,当l固定,r移动,[l r]区间中(maxa - minb)构成递增序列,二分确定(maxa - minb == 0)时r的区间长度,答案累加,nlogn复杂度。关键:发现max 和 min在序列中变化的规律。

#include <iostream>#include <cstdio>#include <cmath>using namespace std;typedef long long LL;const int maxn = 200100;int a[maxn], b[maxn];int ma[maxn][20],mb[maxn][20];int querya(int l, int r){    int v = log2(r - l + 1) + 0.0000000001;    return max(ma[l][v], ma[r - (1<<v) + 1][v]);}int queryb(int l, int r){    int v = log2(r - l + 1) + 0.0000000001;    return min(mb[l][v], mb[r - (1<<v) + 1][v]);}int main(){    int n;    scanf("%d", &n);    for(int i = 1; i <= n; i++){        scanf("%d", &a[i]);    }    for(int i = 1; i <= n; i++){        scanf("%d", &b[i]);    }    for(int i = 1; i <= n; i++) ma[i][0] = a[i];    for(int j = 1; j <= 18; j++){        for(int i = 1; i <= n; i++){            ma[i][j] = max(ma[i][j-1], ma[min(n, i + (1<<(j-1)))][j-1]);        }    }    for(int i = 1; i <= n; i++) mb[i][0] = b[i];    for(int j = 1; j <= 18; j++){        for(int i = 1; i <= n; i++){            mb[i][j] = min(mb[i][j-1], mb[min(n, i + (1<<(j-1)))][j-1]);        }    }    LL ans = 0;    for(int i = 1; i <= n; i++){        int l = i, r = n, mid, qa, qb, rmin = 1, rmax = 0;        while(l <= r){            mid = (l+r)>>1;            qa = querya(i, mid);            qb = queryb(i, mid);            if (qa - qb == 0){                rmin = mid;                r = mid - 1;            }            else if (qa - qb > 0){                r = mid - 1;            }            else{                l = mid + 1;            }        }        l = i, r = n;        while(l <= r){            mid = (l+r)>>1;            qa = querya(i, mid);            qb = queryb(i, mid);            if (qa - qb == 0){                rmax = mid;                l = mid + 1;            }            else if (qa - qb > 0){                r = mid - 1;            }            else{                l = mid + 1;            }        }        //cout<<rmax - rmin + 1<<endl;        ans += rmax - rmin + 1;    }    cout<<ans<<endl;    return 0;}


E 好题,将题意提炼成模型,对于一个insection i,若出现在了p个线段中,由于每次最多选k个线段,则i对最终结果贡献了C(k,p)。对于每一个i分别累加即可,外加一点儿逆元的解法inv(n) = n^(mod - 2),mod为素数。

#include <iostream>#include <map>#include <cstdio>using namespace std;typedef long long LL;const int mod = 1000000007;int f[200010], c[200010];map<int,int>mp;int C(int n, int k){    int sum = (1ll * f[n] * c[k]) % mod;    return (1ll * sum * c[n-k]) % mod;}int Pow(int a, int b){    int re = 1;    while(b){        if (b & 1) re = (1ll * re * a)%mod;        a = (1ll * a * a)%mod;        b >>= 1;    }    return re;}int main(){    int n, k, l, r;    scanf("%d%d", &n, &k);    for(int i = 0; i < n; i++){        scanf("%d%d", &l, &r);        mp[l]++;        mp[r+1]--;    }    f[0] = c[0] = 1;    for(int i = 1; i <= n; i++){        f[i] = (1ll * f[i-1] * i)%mod;        c[i] = Pow(f[i], mod - 2);    }    int cur = mp.begin()->first, sum = 0;    LL ans = 0;    for(map<int,int>::iterator it = mp.begin(); it != mp.end(); it++){        int len = it->first - cur;        if (sum >= k)ans += (1ll * len * C(sum, k))%mod;        ans = (ans >= mod)?ans-mod:ans;        sum += it->second;        cur = it->first;        //cout << ans <<endl;    }    cout << ans <<endl;    return 0;}


0 0
原创粉丝点击