Teams Formation

题意:

给定一长度为 n 的整数序列 $a$,将其复制m次,并接成一条链,每相邻K个相同的整数会消除,然后其他的整数继续结成一条链,直到不能消除为止,求问最终剩余多少个整数。

解法:

首先将长度为n的序列消干净,然后接下来的消除操作必然是在两个序列相交处进行消除,对于接在中间的序列,原消法等价于序列的左侧和右侧不停消除直到无法继续。

分类讨论:

1.序列左右消干净了,这样答案为0

2.序列消得剩下一种元素,统计该元素的总个数,如果K|sum,则为0,不然为sum%K个加上左右侧剩余元素。

3.序列剩下一段元素:

考虑计算消除了多少个:

(1)首先剩余的元素拼在一起 如果有%K!=0的相同元素接在一起 将会消成sum%K

(2)其次中间序列左右消除的个数。

这样就解决了,效率$O(n)$

const int N = 100010;

int n,K,m,tot,a0[N],a[N],b[N];

int main() {
    cin >> n >> K >> m;
    int cnt = n;
    FOR(i,1,n) scanf("%d", &a0[i]);
    b[0] = -1;
    FOR(i, 1, n)
    {
        if(a0[i] == b[tot]) a[tot]++;
        else
        {
            if(tot)
            {
                cnt -= a[tot]-a[tot]%K; a[tot] %= K;
                if(a[tot]==0) tot--;
            }
            if(!tot || a0[i] != b[tot]) a[++tot] = 1, b[tot] = a0[i];
            else a[tot]++;
        }
    }
    cnt -= a[tot]-a[tot]%K;
    a[tot] %= K;
    if(a[tot]==0) tot--;
    if(!tot)
    {
        cout << 0 << endl;
        return 0;
    }
//    FOR(i,1,tot) cout<<a[i]<<'-'<<b[i]<<endl;
    int l=1, r=tot;
    while(l<r)
    {
        if(b[l]!=b[r] || (a[l]+a[r])%K) break;
        l++,r--;
    }
//    debug(l);
//    debug(r);
//    debug(cnt);
    if(l>r)
    {
        cout << 0 << endl;
        return 0;
    }
    else if(l==r)
    {
        if(1ll*a[l]*m%K==0) cout << 0 << endl;
        else cout << cnt-a[l]+1ll*a[l]*m%K << endl;
    }
    else
    {
        LL ans = 1ll*m*cnt,tmp = cnt;
        FOR(i,l,r) tmp -= a[i];
        ans -= 1ll*(m-1)*tmp;
        if(b[l]==b[r]) ans -= 1ll*(m-1)*((a[r]+a[l]) - (a[r]+a[l])%K);
        cout << ans << endl;
    }
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/lawyer/p/7742655.html