Day 1

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;
}
發佈了47 篇原創文章 · 獲贊 26 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章