您的位置:首页 > 其它

【题解】Codeforces731D 80-th Level Archeology

2018-04-11 16:25 375 查看
戳我

题目解释:

有n个数列,每个数列长度可能不一样,同时有一个c,你有一种操作,让这n个数列中所有小于c的数都加1,所有等于c的数变成0.问你最少可以操作几次可以让这n个数列满足字典序

我们可以发现,对于任意两个相邻的数列,操作数k有一个符合的区间。只要操作数k在这个区间里面,上面的数列字典序总小于下面的数列。说得通俗一点,有n-1个区间(有特殊情况,看代码),要求这n-1个区间的交。

怎么做这个问题呢,我们可以采取差分+前缀和的方式进行处理,具体方法就是区间两端位置放个++和–,统计时从前到后加起来就可以了。

Codes

#include<cstdio>
#include<vector>
#include<cstring>
using namespace std;
const int MAXN = 1e6 + 10;
const int MAXC = 1e7 + 10;
vector<int> words[MAXN];
int cnt[MAXC], n, c;
void calc(int a, int b)
{
int index = 0;
while (index < words[a].size() && index < words[b].size()) //失配位置查询
{
if (words[a][index] != words[b][index]) break;
index++;
}
if (index < words[a].size() && index < words[b].size()) // 失配位置在a, b中
{
if (words[a][index] < words[b][index]) // 失配位置a小于b
{
cnt[0]++;
cnt[c - words[b][index] + 1]--;
cnt[c - words[a][index] + 1]++;
cnt[c]--;
}
else
{
cnt[c - words[a][index] + 1]++;
cnt[c - words[b][index] + 1]--;
}
}
else if (index == words[a].size() && index != words[b].size()) //a比b短
{
cnt[0]++;
cnt[c]--;
}
else if (index != words[a].size() && index == words[b].size()); // a比b长,无解
else //a和b一样长
{
cnt[0]++;
cnt[c]--;
}
}
int main()
{
scanf("%d%d", &n, &c);
for (int i = 1;i <= n;i++)
{
int len, w;
scanf("%d", &len);
while (len--)
{
scanf("%d", &w);
words[i].push_back(w);
}
}
for (int i = 1;i <= n - 1;i++) calc(i, i + 1);
bool flag = false;
int sum = 0;
for (int i = 0;i < c;i++)
{
sum += cnt[i];
if (sum == n - 1)
{
flag = true;
printf("%d\n", i);
return 0;
}
}
if (!flag) printf("-1\n");
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: