有一根绳子,从左到右分为 n 段,每一段长度相同,厚度为 1。共有 m 种颜色,第 i 段的颜色为 ai。
有两种操作:
(1)将绳子从某相邻两段的交点处折叠,将对应的段拧在一起。必须保证对应的段颜色相同,拧在一起之后的厚度为原先两段之和。例如,现在绳子的颜色为 1 2 2 1 3,厚度为 1 2 1 3 1,我们可以在第 2、3 两段的交点处折叠绳子,颜色变为 2 1 3,厚度变为 3 4 1。
(2)将某一段绳子染为任意一种颜色,代价为这一段的厚度。
对于每种颜色,你需要求出将绳子折叠至只剩两段并且至少有一段是这种颜色的最小代价。
第一行两个整数 n,m,第二行 n 个整数 a1~an。
m 行每行一个整数,第 i 行表示第 i 种颜色的答案。
5 3
1 2 3 3 2
2
1
1
7 3
1 2 2 1 3 3 3
2
2
2
10 3
2 2 1 1 3 3 2 1 1 2
3
3
4
Subtask 1 (8pts):n<=15,m<=10。
Subtask 2 (33pts):n<=10^5,m<=10。
Subtask 3 (12pts):n<=10^5,m<=500。
Subtask 4 (20pts):n<=10^5,m<=5000。
Subtask 5 (27pts):无特殊限制。
对于全部数据,2<=n<=10^6,1<=m<=n,1<=ai<=m,保证 m 种颜色都至少出现一次。
我们可以考虑一下反着来,如果最后符合要求得是什么样的
那么每翻折一下,就会发现其实翻折方向的那个重复了两次
那么经过无数次翻折后,除了两侧的可能有例外,其他的都会是两个两个的
而且所有的这些情况最后都可以合成为只有两个,因为你可以翻折出任意形态
那么现在只需讨论几种情况,中间贪心就可以选择了
枚举每种颜色作为首选,选择贡献次数最多的另一种颜色辅助,就可以求出最小的填色数了
中间维护最大值可以O(1)做的,也可以用线段树rua
#include
using namespace std;
int n,m,cnt[1000005],a[1000005],tong[1000005],maxa,other[1000005];
int another[1000005],vis[1000005],ans;
int minn(int x,int y){if(xy) return x;return y;}
vector vec[1000005];
int read()
{
char c;int x;
for(c=getchar();c!='-'&&(c>'9'||c<'0');c=getchar());
if(c=='-')
{
x=0;
for(c=getchar();c>='0'&&c<='9';c=getchar()) x=x*10+c-'0';
return -x;
}
else
{
x=c-'0';
for(c=getchar();c>='0'&&c<='9';c=getchar()) x=x*10+c-'0';
return x;
}
}
int main()
{
cin>>n>>m;
for(int i=1;i<=n;i++)
{
a[i]=read();
vec[a[i]].push_back(i);
cnt[a[i]]++;
}
if(m==1)
{
printf("0\n");
return 0;
}
for(int i=1;i<=m;i++)
tong[cnt[i]]++,maxa=maxx(maxa,cnt[i]);
for(int i=2;i+1<=n;i+=2)
another[i+1]=i,another[i]=i+1;
for(int i=1;i<=n;i+=2)
other[i+1]=i,other[i]=i+1;
for(int i=1;i<=m;i++)
{
int times=0;
for(vector :: iterator it=vec[i].begin(),ed=vec[i].end();it!=ed;it++)
{
int y=*it;
times++;
if(vis[y]||!another[y]) continue;
vis[*it]=vis[another[y]]=1;
tong[cnt[a[y]]]--;cnt[a[y]]--;tong[cnt[a[y]]]++;
tong[cnt[a[another[y]]]]--;cnt[a[another[y]]]--;tong[cnt[a[another[y]]]]++;
if(!tong[maxa]) maxa--;
if(!tong[maxa]) maxa--;
}
ans=n-(times+maxa);
for(vector :: iterator it=vec[i].begin(),ed=vec[i].end();it!=ed;it++)
{
int y=*it;
if(!vis[y]||!another[y]) continue;
vis[*it]=vis[another[y]]=0;
tong[cnt[a[y]]]--;cnt[a[y]]++;tong[cnt[a[y]]]++;
tong[cnt[a[another[y]]]]--;cnt[a[another[y]]]++;tong[cnt[a[another[y]]]]++;
if(tong[maxa+1]) maxa++;
if(tong[maxa+2]) maxa+=2;
}
times=0;
for(vector :: iterator it=vec[i].begin(),ed=vec[i].end();it!=ed;it++)
{
int y=*it;
times++;
if(vis[y]||!other[y]) continue;
vis[*it]=vis[other[y]]=1;
tong[cnt[a[y]]]--;cnt[a[y]]--;tong[cnt[a[y]]]++;
tong[cnt[a[other[y]]]]--;cnt[a[other[y]]]--;tong[cnt[a[other[y]]]]++;
if(!tong[maxa]) maxa--;
if(!tong[maxa]) maxa--;
}
ans=minn(ans,n-(times+maxa));
for(vector :: iterator it=vec[i].begin(),ed=vec[i].end();it!=ed;it++)
{
int y=*it;
if(!vis[y]||!other[y]) continue;
vis[*it]=vis[other[y]]=0;
tong[cnt[a[y]]]--;cnt[a[y]]++;tong[cnt[a[y]]]++;
tong[cnt[a[other[y]]]]--;cnt[a[other[y]]]++;tong[cnt[a[other[y]]]]++;
if(tong[maxa+1]) maxa++;
if(tong[maxa+2]) maxa+=2;
}
printf("%d\n",ans);
}
return 0;
}