BZOJ4382[POI2015] Podział naszyjnika

来源:互联网 发布:弹丸论破未来篇 知乎 编辑:程序博客网 时间:2024/06/14 02:45

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 longusing 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;}
0 0
原创粉丝点击