题目:疯狂的馒头
Description
小t十分喜欢吃馒头。兴奋之下他一下子买了N个馒头请所有认识他的人吃。
但是小t不喜欢白色,喜欢红色、黄色、绿色等鲜艳的颜色。于是他把所有白色的馒头排成一列。然后进行M次染色操作。每个染色操作都是用一个神奇的刷子把连续的多个馒头染成特定的某种颜色。一个馒头最终的颜色是最后一次染它的颜色。如果一个馒头没有被染过色,那么它的颜色就是白色。
现在小t已经定好了染色计划:在第i次染色操作中,把第(i×p + q)mod N + 1个馒头和第(i×q + p)mod N + 1个馒头之间的馒头染成颜色i,其中p,q是特定的两个正整数。他想立即知道最后每个馒头的颜色。你能帮他吗?
Input
第一行四个正整数N,M,p,q。
Output
一共输出N行,第i行表示第i个馒头的最终颜色(如果最终颜色是白色就输出0)。
Sample Input
4 3 2 4
Sample Output
2 2 3 0
HINT
20%数据满足:1≤n≤1000,1≤m≤10000;
40%数据满足:1≤n≤10000,1≤m≤100000;
100%数据满足:1≤n≤1000000,1≤m≤10000000;1≤m*p+q,m*q+p≤2^31-1;
题解:
典型的并查集题;
因为最终的颜色取决于最后一次染得色,所以要倒序枚举;
fa[j]表示j后面第一个没有被染过色的点;
具体见代码;
1 #include<iostream> 2 #include<cstdio> 3 #define ll long long 4 using namespace std; 5 const int N=10000010; 6 int fa[N],ans[N]; 7 ll n,m,p,q; 8 int find(ll x){ //非递归寻找父亲节点,递归会爆re; 9 int r=x,pre; 10 while(r!=fa[r]) r=fa[r]; 11 while(x!=r){ 12 pre=fa[x]; 13 fa[x]=r; 14 x=pre; 15 } 16 return r; 17 } 18 inline void swap(ll &x,ll &y){ 19 ll z=x;x=y;y=z; 20 } 21 int main() 22 { 23 scanf("%lld%lld%lld%lld",&n,&m,&p,&q); 24 for(int i=1;i<=n+2;i++) fa[i]=i; //fa[i]为i后面第一个没有被染色的位置; 25 for(int i=m;i>=1;i--){ //染色结果为最后一次染的颜色,所以倒叙枚举; 26 ll l=((ll)i*p+q)%n+1; 27 ll r=((ll)i*q+p)%n+1; 28 if(l>r) swap(l,r); //每次都保证l<r; 29 for(int j=find(l);j<=r;j=find(j)){ 30 ans[j]=i; //记录答案,更新fa; 31 fa[j]=j+1; 32 } 33 } 34 for(int i=1;i<=n;i++){ 35 printf("%d\n",ans[i]); 36 } 37 return 0; 38 }