问题分析:
虽然不能严谨的证明,但是其实自己模拟几组数据再操作一下就发现,无论怎么操作只要每个人的愿望座位定下来,总怒气值就是定值,都不会变(只不过看是谁生气而已 笑)。
其实最简单的或者说最容易想到的方法就是按照题目的说法,用一个数组来记录位置是否被占用,占用就检索下一个是否被占用,最后用下标相减就是怒气值。
但这个算法的时间复杂度可是O(N^2)呀!我们又看到了题目熟悉的0<m<=n<=100000
机智的我又看了一下提交的情况,一半都是TLE超时......说明这个算法不太行。
emmmm也许你和我一样在比赛时一下子失去了方向。
现在比完静下心来思考,其实在证明出无论如何安排总怒气值不变后,难度就降低很多了,你需要考虑的就是如何去计算出结果而已。
我们就按照椅子的顺序来考虑吧,因为每个嘉宾要么直接做到心仪的位置,要么直接往后走,不存在往前走的情况,那么我们就可以设置一个endflag来表示到目前这个椅子为止,坐的最右边的嘉宾的位置。然后后面先判断与endflag的大小关系,再决定是否要计算angry和更新endflag 的方法。
AC代码:
#include <bits/stdc++.h>
using namespace std;
int n[100010];
int main()
{
int total,guest;
int t;
int endflag=0;
//一定要ll不然会WA
long long angry=0;
cin >> total >> guest;
//用n数组标记每个椅子有多少嘉宾喜欢
for ( int i=1; i<=guest; ++i )
cin >> t, n[t]++;
for ( int i=1; i<=total; ++i)
{
//没有嘉宾喜欢的椅子就不用判断
if ( n[i] )
{
//若大于endflag说明这个位置还没有人做 可以占用
if ( i>endflag )
{
if ( n[i]==1 )
endflag = i;
//如果很多人同时喜欢这个位置,那么根据人数更新endflag同时计算angry
else
{
endflag = i+n[i]-1;
t = 1;
for ( int j=1; j<=n[i]-1; ++j )
angry += t++;
}
}
else
{
//若小于,说明这个位置之前的位置肯定已经做满了
//因为我们是按照椅子的顺序进行遍历的
//所以这个时候我们就要用另一种方式更新endflag和angry
endflag += n[i];
t = endflag;
for ( int j=1; j<=n[i]; ++j )
angry += (t-i),t--;
}
}
}
if ( endflag > total )
cout << "-1";
else
cout << angry;
}如果上面更新endflag和angry的计算方法你还是有点不懂,推荐你以
10 8 1 4 4 5 5 6 6 6
的例子自己在草稿纸上写写就会明白的~
当然,我这个还是太过冗长,可以优化。
比如我可以直接存放每个嘉宾的心仪位置
然后通过endflag=max(m[i],endflag+1)的方式更新,这样就不用讨论那么多种情况了。

京公网安备 11010502036488号