Day 1

来源:互联网 发布:用vb制作倒计时 编辑:程序博客网 时间:2024/05/16 14:06

B. Friends and Subsequences


[Problems]
There are two boys, every one of them has a integer sequencea a and b of length n(2*10^5). Now Being given a query of the form of pair of integers (l, r), you should judge whether the max(ai) l<=i<=r and min(bi) l <=i<=r are equal.
thus for how many pairs is satisfied.
[solution]
首先考虑划块法,对于(l,r)转移到r+1,如果此时min>max, 则忽略,如果min=max,则累加一,关键是如果min

#include<cstdio>#include<iostream>using namespace std;const int N = 200000 + 500;int ma[N][25], mi[N][25];int a[N], b[N];void RMQ_init(int n){    int k = 0;    while(1 << (k + 1) <= n)        k++;    for(int i = 1; i <= n; i++)    {        ma[i][0] = a[i];        mi[i][0] = b[i];    }    for(int j = 1; j <= k; j++)        for(int i = 1; i + (1 << j) - 1 <= n; i++)    {        ma[i][j] = max(ma[i][j - 1], ma[i + (1 << (j - 1))][j - 1]);        mi[i][j] = min(mi[i][j - 1], mi[i + (1 << (j - 1))][j - 1]);      //  printf("ma[%d][%d]=%d\n", i, j, ma[i][j]);      //  printf("mi[%d][%d]=%d\n", i, j, mi[i][j]);    }}int querya(int l, int r){    int k = 0;    while(1 << (k + 1) <= (r - l + 1))        k++;    return max(ma[l][k], ma[r - (1 << k) + 1][k]);}int queryb(int l, int r){    int k = 0;    while(1 << (k + 1) <= (r - l + 1))        k++;    return min(mi[l][k], mi[r - (1 << k) + 1][k]);}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]);    RMQ_init(n);    long long tot = 0;    for(int i = 1; i <= n; i++)        if (a[i] <= b[i])    {        int l = i, r = n;        int ans1 = 0;        while(l <= r)        {            int mid = (l + r ) >> 1;            int maxi = querya(i, mid);            int mini = queryb(i, mid);            if (mini > maxi)            {                ans1 = mid;                l = mid + 1;            } else                r = mid - 1;        }        l = i;        r = n;        int ans2 = 0;        while(l <= r)        {            int mid = (l + r ) >> 1;            int maxi = querya(i, mid);            int mini = queryb(i, mid);            if (mini < maxi)            {                ans2 = mid;                r = mid - 1;            } else                l = mid + 1;        }      //  printf("%d:%d---->%d\n", i, ans1, ans2);        if (ans1 + ans2 != 0)        {            if (ans1 == 0)                tot += ans2 - i;            if (ans2 == 0)                tot += n - ans1;            if (ans1 != 0 && ans2 != 0)                tot += ans2 - ans1 - 1;        }        else        tot += n - i + 1;    }    cout<<tot;    return 0;}

C. Array Division

[Problems]
Vasya has an array a consisting of positive integer numbers, he will moving one element from his position to any position so that divide this array into two non-empty consecutive parts, the sum of all elements in the first part equals the sum of elements.
print YES if vasya can divide the array after moving one element.Otherwise print NO.
[solution]
第一思路是把从开头累加前缀和sum1,在sum1 刚好大于第二部分的sum2,判断sum1是否含有(sum1-sum2)/2这个元素即可,这是将一个元素往后移动的过程,然后反向搞一遍即可。
但是实际上将一个元素往后移动以后,两个部分的界限可能因此变化,所以我们考虑这个方法是有局限性的
正解:既然界限可能改变,那我们就枚举界限,然后判断是从可以从一个部分移动一个元素到另一部分,然后两个部分的sum相同,这是用到stl的set既可以判断了。
即枚举i,使得将此序列分成(1,i)(i+1,n)两部分,判断累加和较大的那部分是否有元素
(sum1-sum2)/2 即可
注意i是可以累加到n的,因为存在我把第一部分为(1,n),第二部分为空,然后把一个元素移动到第二个元素就可以了
[Code]

#include<cstdio>#include<iostream>#include<set>using namespace std;typedef long long ll;const int N = 100000 + 500;ll a[N];set<ll> s1, s2;int main(){    int n;    scanf("%d", &n);    ll sum = 0;    for(int i = 1; i <= n; i++)    {        cin>>a[i];        sum += a[i];    }    ll sum1 = 0, sum2 = 0;    if (sum % 2 != 0)    {        printf("NO\n");        return 0;    }    bool ok = false;    for(int i = 1; i <= n; i++)    {        s1.insert(a[i]);        sum1 += a[i];        sum2 = sum - sum1;        if (sum1 == sum2)        {            ok = true;            break;        }        if (sum1 > sum2 && (sum1 - sum2) % 2 == 0)            {                ll x = (sum1 - sum2) / 2;                if (s1.count(x) != 0)                {                    ok = true;                    break;                }            }    }    sum2 = 0;    for(int i = n; i >= 1; i--)    {        s2.insert(a[i]);        sum2 += a[i];        sum1 = sum - sum2;        if (sum1 == sum2)        {            ok = true;            break;        }        if (sum2 > sum1 && (sum2 - sum1) % 2 == 0)        {            ll x = (sum2 - sum1) / 2;            if (s2.count(x) != 0)            {                ok = true;                break;            }        }    }    printf("%s\n", ok ? "YES" : "NO");    return 0;}