BZOJ4382[POI2015] Podział naszyjnika

BZOJ4382[POI2015] Podział naszyjnika

Description

長度爲n的一串項鍊,每顆珠子是k種顏色之一。 第i顆與第i-1,i+1顆珠子相鄰,第n顆與第1顆也相鄰。

切兩刀,把項鍊斷成兩條鏈。要求每種顏色的珠子只能出現在其中一條鏈中。

求方案數量(保證至少存在一種),以及切成的兩段長度之差絕對值的最小值。

Input

第一行n,k(2<=k<=n<=1000000)。顏色從1到k標號。

接下來n個數,按順序表示每顆珠子的顏色。(保證k種顏色各出現至少一次)。

Output

一行兩個整數:方案數量,和長度差的最小值

Sample Input

9 5

2 5 3 2 2 4 1 1 3

Sample Output

4 3

HINT

四種方法中較短的一條分別是(5),(4),(1,1),(4,1,1)。相差最小值6-3=3。

Solution:

考慮怎麼樣的情況下可以分割。我們按照前綴給環上可以分割的點進行編號:

1

可以發現如果前綴相同,此兩點之間就可以斷開,當然,因爲是環形,最後一個該顏色點之後該顏色的點前綴就應編號爲0。於是對於每個點都對應一個k 元組(sum1,sum2,sum3,sum4,sum5...sumk) ,當且僅當兩個k 元組相同時,這兩點可以連邊。於是考慮哈希,這道題就解的差不多了,注意一下Hash值的累加用O(1)轉移,至於最小值的話,根據單調性隨便弄一下就好了。

這題還卡哈希,用了雙哈希才過。

#include<stdio.h>
#include<ctype.h>
#include<string.h>
#include<iostream>
#include<algorithm>
#define B1 200019
#define B2 200011
#define M 1000005
#define P1 1000000007
#define P2 1000000009
#define ll long long
using namespace std;
struct Node{
    int id,res1,res2;
    bool operator <(const Node &a)const{
        if(res1!=a.res1)return res1<a.res1;
        else if(res2!=a.res2)return res2<a.res2;
        else return id<a.id;
    }
}Q[M];
int A[M],Base1[M],Base2[M],ed[M],cnt[M];
void Rd(int &res){
    char c;res=0;
    while(c=getchar(),!isdigit(c));
    do{
        res=(res<<1)+(res<<3)+(c^48);
    }while(c=getchar(),isdigit(c));
}
int main(){
    int n,k;
    Rd(n);Rd(k);
    for(int i=1;i<=n;i++)Rd(A[i]);
    Base1[0]=Base2[0]=1;
    for(int i=1;i<=k;i++){
        Base1[i]=(1LL*Base1[i-1]*B1)%P1;
        Base2[i]=(1LL*Base2[i-1]*B2)%P2;
    }
    memset(ed,-1,sizeof(ed));
    for(int i=n;i>=1;i--){
        if(~ed[A[i]])continue;
        ed[A[i]]=i;
    }
    int res1=0,res2=0;
    for(int i=1;i<=n;i++){
        cnt[A[i]]++;
        res1=(res1+Base1[A[i]])%P1;
        res2=(res2+Base2[A[i]])%P2;
        if(ed[A[i]]==i)res1=((res1-1LL*Base1[A[i]]*cnt[A[i]])%P1+P1)%P1;
        if(ed[A[i]]==i)res2=((res2-1LL*Base2[A[i]]*cnt[A[i]])%P2+P2)%P2;
        Q[i].id=i;Q[i].res1=res1;Q[i].res2=res2;
    }
    sort(Q+1,Q+n+1);
    int Half=(n+1)/2,ans=n;
    ll cnt=0;
    for(int i=1;i<=n;){
        int nxt=i;
        while(nxt<=n&&Q[nxt].res1==Q[i].res1&&Q[nxt].res2==Q[i].res2)nxt++;
        cnt+=1LL*(nxt-i)*(nxt-i-1)/2;
        for(int L=i,R=i;R<nxt;R++){
            while(L<R&&Q[R].id-Q[L].id>=Half)L++;
            int rs1=abs(n-2*(Q[R].id-Q[L].id));
            if(L>i){
                int rs2=abs(n-2*(Q[R].id-Q[L-1].id));
                if(rs2<rs1)rs1=rs2;
            }
            if(rs1<ans)ans=rs1;
        }
        i=nxt;
    }
    cout<<cnt<<' '<<ans<<endl;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章