Teams Formation CodeForces - 878B (思维+模拟)

Teams Formation

CodeForces - 878B

This time the Berland Team Olympiad in Informatics is held in a remote city that can only be reached by one small bus. Bus has n passenger seats, seat i can be occupied only by a participant from the city ai.

Today the bus has completed m trips, each time bringing n participants. The participants were then aligned in one line in the order they arrived, with people from the same bus standing in the order of their seats (i. e. if we write down the cities where the participants came from, we get the sequence a1, a2, ..., an repeated m times).

After that some teams were formed, each consisting of k participants form the same city standing next to each other in the line. Once formed, teams left the line. The teams were formed until there were no k neighboring participants from the same city.

Help the organizers determine how many participants have left in the line after that process ended. We can prove that answer doesn't depend on the order in which teams were selected.


Input

The first line contains three integers n, k and m (1 ≤ n ≤ 105, 2 ≤ k ≤ 109, 1 ≤ m ≤ 109).

The second line contains n integers a1, a2, ..., an (1 ≤ ai ≤ 105), where ai is the number of city, person from which must take seat i in the bus.

Output

Output the number of remaining participants in the line.

Examples
Input
4 2 5
1 2 3 1
Output
12
Input
1 9 10
1
Output
1
Input
3 2 10
1 2 1
Output
0
Note

In the second example, the line consists of ten participants from the same city. Nine of them will form a team. At the end, only one participant will stay in the line.

题意:

给出一个长为n的序列,将其重复m次,连续相等的k的个元素可以被消除,问最后剩余多少个元素。

思路:

这道题我是看的网上的博客,看了半天终于看明白了,所以这里我就按照那篇博客的思路具体解释一下

首先我们先考虑单个串,如果单个串中有恰好k的倍数个连续相同字符,那么我们应该先将其消除,那么第一步我们遍历数组,这里我们需要用到一个pair数组,这个数组是整道题目的关键,pari数组中前面存数值,后面存个数,这样如果我们遍历到的数字和前一个相同也就是找到了连续相同的,我们只需要给顶部的元素的st[top].second+1,如果发现和前一个元素不同说明已经不连续相同了,这时候我们再把这个数放进去,这样的好处就是我们pair数组中用一个数字和其个数代表了连续相等的串,这样我们只需要判断st[i].second%k是否等于0就可以。这样对于初始串的处理就结束了,我们就得到的消去连续的后的单个串的个数我们记为rec

然后我们观察,发现对于每两个串相连,其实就是一个串的首尾相连把连续相同的k个消去,这样我们还是对一个串处理,我们继续处理pair数组,用两个下标l,r从两边向中间缩,如果两头数字相同并且,他们的个数之和恰好是k的倍数,那么这一堆全都可以消去,这样我们让l++,r++,记录下消除的个数,一直到两头数字不能完全消除为止,用while循环实现,每个串消除的首尾总个数我们记为rec2,同时我们发现第一个串的首和最后一个串尾可能不会接触,那么我们可以确定一定会减去m-1个rec2

1 1 3 2 1 k = 3三个相连 1 1 3 2 1 1 1 3 2 1 1 1 3 2 1消除两个的,两头的暂时不会接触

此时循环结束后会有两种大情况

一、只剩下了一种数字

(不是一个,因为这一种数字可能多个,注意pari数组的意义)

二、剩下多种数字

对于第一种,因为每种数字都属于一个串也就是有m个,因此又分成两种情况:

1、总共m*每种的个数如果是k的倍数,直接全部消去,并且要十分注意,中间都消除了,那么这是首尾就有碰面了,这样又得消除一个rec2,一共就消除了m个rec2

如串1 1 3 1 , k = 3,三个相连 1 1 3 1 1 1 3 1 1 1 3 1

先消去了111,然后得到了 1 1 3 3 3 1,然后就可以消去3然后就到了 1 1 1,就可以消去1了,首尾碰面了。

2、另一种当然就是不能被k整除,那么我们就只能减去k的倍数的个数

还是串1 1 3 1 k = 3,四个相连1 1 3 1 1 1 3 1 1 1 3 1 1 1 3 1

得到1 1 3 3 3 3 1,这个时候中间的3只能消去3个(3的1倍)得到1 1 3 1

对于第二种,

1、如果首尾数字相同,说明他们总数不是k的倍数,但是我们还是要减去小于它的k的倍数

2、如果不同那么就直接减掉我们之前统计的消掉的就好了

注意用long long

code:

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
typedef long long ll;
const int maxn = 1e5+10;
ll a[maxn];
pair<ll,ll> st[maxn];
ll top,n,m,k,l,r,rec,rec2;
ll ans;
int main(){
    cin >> n >> k >> m;
    for(ll i = 1; i <= n; i++)
        cin >> a[i];
    for(ll i = 1; i <= n; i++){
        if(!top || st[top].first != a[i])
            st[++top] = make_pair(a[i],1);
        else
            st[top].second = (st[top].second + 1) % k;
        if(st[top].second == 0) top--;
    }
    for(ll i = 1; i <= top; i++){
        rec += st[i].second;
    }
    l = 1,r = top;
    while(l < r && st[l].first == st[r].first && (st[l].second + st[r].second) % k == 0){
        rec2 += st[l].second + st[r].second;
        l++;
        r--;
    }
    if(l == r){
        if(st[l].second * m % k == 0)
            ans -= rec2;
        ans += m * rec - rec2 * (m - 1) - (st[l].second * m / k * k);
    }
    else{
        if(st[l].first == st[r].first)
            rec2 += (st[l].second + st[r].second) / k * k;
        ans = m * rec - rec2 * (m - 1);
    }
    cout << ans << endl;
    return 0;
}


猜你喜欢

转载自blog.csdn.net/codeswarrior/article/details/80094168