Codeforces731D 80-th Level Archeology

考虑将两个单词变成有序,我们可以得到一个或者两个旋转次数的区间。

然后考虑将两组单词变成有序,比如[l,mid]和[mid+1,r],对于mid和mid+1这两个单词我们可以求出使他们有序的旋转次数的区间。

然后将这个区间与[l,mid]的区间以及[mid+1,r]的区间求交,就可以得到使[l,r]有序的旋转次数的区间。

上面这个过程我们可以用分治来进行,区间求交可以用扫描线法。

#include <bits/stdc++.h>
using namespace std;

vector<int> words[500010];
int cnt[1000010];
int n, c;
int tot = 0;

void calc(int a, int b)
{
    int idx = 0;
    while (idx < words[a].size() && idx < words[b].size())
    {
        if (words[a][idx] != words[b][idx])
            break;
        idx++;
    }
    if (idx < words[a].size() && idx < words[b].size())
    {
        if (words[a][idx] < words[b][idx])
        {
            cnt[0]++;
            cnt[c - words[b][idx] + 1]--;
            cnt[c + 1 - words[a][idx]]++;
            cnt[c]--;
            tot++;
        }
        else
        {
            cnt[c + 1 - words[a][idx]]++;
            cnt[c - words[b][idx] + 1]--;
            tot++;
        }
    }
    else if (idx == words[a].size() && idx != words[b].size())
    {
        cnt[0]++;
        cnt[c]--;
        tot++;
    }
    else if (idx != words[a].size() && idx == words[b].size())
        tot++;
    else
    {
        cnt[0]++;
        cnt[c]--;
        tot++;
    }
}

void divideConquer(int l, int r)
{
    if (l == r)
        return;
    int mid = (l + r) >> 1;
    divideConquer(l, mid);
    divideConquer(mid + 1, r);
    calc(mid, mid + 1);
}

int main()
{
    scanf("%d%d", &n, &c);
    for (int i = 0; i < n; i++)
    {
        int l, w;
        scanf("%d", &l);
        while (l--)
        {
            scanf("%d", &w);
            words[i].push_back(w);
        }
    }
    divideConquer(0, n - 1);
    bool ok = false;
    int sum = 0;
    for (int i = 0; i < c; i++)
    {
        sum += cnt[i];
        if (sum == tot)
        {
            ok = true;
            printf("%d", i);
            break;
        }
    }
    if (!ok)
        printf("-1");
    return 0;
}

 

posted @ 2016-10-18 23:22  iRedBean  阅读(378)  评论(0编辑  收藏  举报