长度为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;
}