[bzoj 4382--POI2015]Podział naszyjnika

長度爲n的一串項鍊,每顆珠子是k種顏色之一。 第i顆與第i-1,i+1顆珠子相鄰,第n顆與第1顆也相鄰。
切兩刀,把項鍊斷成兩條鏈。要求每種顏色的珠子只能出現在其中一條鏈中。 求方案數量(保證至少存在一種),以及切成的兩段長度之差絕對值的最小值。

首先我們可以發現如果只考慮一種顏色,那麼只要相鄰的兩顆顏色相同的之間選兩個間隔斷開就可以了,這樣如果有x顆顏色相同,就會有x個區間,每一個區間裏的任意兩個間隔都可以滿足條件。
現在要使全部顏色滿足條件,就只需要那兩個斷點都同時存在於k種顏色中每一種顏色的同一個區間。有一個很顯然的性質,那就是每一個間隔都可以屬於每一種顏色的一個且僅一個區間內。那每一個間隔都可以用一個k位數表示,如果兩個間隔的k位數相同,那麼它們就可以作爲一種方案。
那麼這題就算做完了,k位數可以用hash壓縮,而求最小值可以用單調隊列。

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<cstdlib>
#include<queue>
#define P 1333331
using namespace std;
deque<int>q;
inline int read()
{
    int x=0,f=1;char ch=getchar();
    while(ch<'0' || ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0' && ch<='9')x=x*10+ch-'0',ch=getchar();
    return x*f;
}
inline void write(int x)
{
    if(x<0)putchar('-'),x=-x;
    if(x>9)write(x/10);
    putchar(x%10+'0');
}
struct node
{
    unsigned long long d;int p;
}wy[1000010];
bool cmp(node a,node b)
{
    if(a.d==b.d)return a.p<b.p;
    else return  a.d<b.d;
}
int id[1000010],cnt[1000010],ul[1000010];
unsigned long long bin[1000010];
int main()
{
    //freopen("4382.in","r",stdin);
    //freopen("4382.out","w",stdout);
    int n=read(),k=read();
    bin[0]=1;for(int i=1;i<k;i++)bin[i]=bin[i-1]*P;
    for(int i=1;i<=n;i++){id[i]=read(),cnt[id[i]]++;}
    unsigned long long now=0;
    for(int i=1;i<=k;i++)now+=cnt[i]*bin[i-1],ul[i]=cnt[i];
    for(int i=1;i<=n;i++)
    {
    	now-=bin[id[i]-1]*cnt[id[i]];
    	cnt[id[i]]--;if(!cnt[id[i]])cnt[id[i]]=ul[id[i]];
    	now+=bin[id[i]-1]*cnt[id[i]];
    	wy[i].d=now,wy[i].p=i;
    }sort(wy+1,wy+n+1,cmp),wy[n+1].d=0;
    int ans=n,lt=1,tot=0;long long sum=0;
    for(int i=1;i<=n+1;i++)
    {
        if(wy[i].d!=wy[i-1].d)
        {
            sum+=1LL*tot*(tot-1)/2;tot=0;
            q.clear();
            for(int j=lt;j<i;j++)
            {
                while(q.size()>1)
                {
                    if(abs(n-2*(wy[j].p-q[0]))>=abs(n-2*(wy[j].p-q[1])))q.pop_front();
                    else break;
                }
                if(q.size()>0)ans=min(ans,abs(n-2*(wy[j].p-q[0])));
                q.push_back(wy[j].p);
            }
            lt=i;
        }tot++;
    }
    printf("%lld %d\n",sum,ans);
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章