“柴门闻犬吠,风雪夜归人”,冬天,不期而至。千里冰封,万里雪飘。空中刮起了鸭毛大雪。雪花纷纷,降落人间。 美能量星球(pty 在 spore 上的一个殖民地)上的人们被这美景所震撼。但是 pty 却不高兴,他不喜欢白色的世界,他觉得这样太单调了。所以他想对雪花进行染色,让世界变得多彩些。
题目描述
现在有 n 片雪花排成一列。 pty 要对雪花进行 m 次染色操作,第 i 次染色操作中,把第((i×p+q)modn)+1 片雪花和第 ((i×q+p)modn)+1 片雪花之间的雪花(包括端点)染成颜色 i。其中 p,q 是给定的两个正整数。他想知道最后 n 片雪花被染成了什么颜色。没有被染色输出 0。
输入格式
输入共四行,每行一个整数,分别为 n,m,p,q,意义如题中所述。
输出格式
输出共 n 行,每行一个整数,第 i 行表示第 i 片雪花的颜色。
题解:这题还怪有意思的嘞。一开始会去想双链表,后来发现过不了。染色有个规律:后染的会覆盖前染的,所以我们没有必要模拟过程。直接从后往前扫,根据他的规则染色,过于避免颜色被覆盖的问题,我们可以用并查集,染过色的区块我们使它的父亲为最靠前没染色的区块,这样节省了大量搜索的时间(有点像KMP)。
然后用一个数组储存颜色,就这样(还有些细节要注意):
#include<bits/stdc++.h>
using namespace std;
const int INF=1e6+3;
int n,m,p,q,fa[INF],color_[INF];
int find_(int x)
{
if(x==fa[x])
{
return x;
}
return fa[x]=find_(fa[x]);
}
void paint_()
{
for(int i=m;i>=1;i--)//从后往前扫
{
int l1=(i*p+q)%n+1,r1=(i*q+p)%n+1;
if(l1>r1)
{
swap(l1,r1);//保证循环有效(原题说之间,没说哪个大)
}
for(int j=r1;j>=l1;)//这个j也需要从后往前扫,避免回溯卡死
{
int index=find_(j);
if(index==j)//如果这个点没染过
{
color_[j]=i;//储存颜色
fa[j]=find_(j-1);//将它的父亲设为上一个点
}
j=fa[j];//维护
}
}
}
int main()
{
cin>>n>>m>>p>>q;
for(int i=1;i<=n;i++)
{
fa[i]=i;//初始化!!
}
paint_();
for(int i=1;i<=n;i++)
{
printf("%d\n",color_[i]);
}
}