简要题意
给定一个长度为 \(n\) 的序列 \(a\),值域为 \([0,m]\)。将该序列循环右移 \(1\) 位,并记录下当前序列,重复该过程 \(n\) 次。将得到的序列按字典序升序排序,构成一个 \(n \times n\) 的矩阵,给出该矩阵的最后一列,询问矩阵的第一行。
数据范围:\(n \le 10^3,m \le 9\)。
分析
循环位移有很多有意思的性质。
我们首先可以知道该矩阵的第一列,就是最后一列排序升序的结果。
那么我们观察到:将某一行循环右移后得到的序列,一定在矩阵里。这不废话
那么我们再观察:如果将所有以 \(x\) 结尾的行都循环右移一位,那么得到的行就是矩阵中所有以 \(x\) 开头的行。这不还是废话
那么我们再观察:这些序列在操作前后的相对顺序没有改变。为什么?
证明:我们假设对于两个以 \(x\) 结尾的序列 \(T_1,T_2\)( \(T_1\) 排在 \(T_2\) 前),有 \(T_1=t_1+x,T_2=t_2+x\)。因为 \(T_1 < T_2\)(字典序比较,下同),那么有 \(T_1<T_2 \rightarrow t_1+x < t_2+x \rightarrow t_1<t_2\)。那么有 \(x+t_1<x+t_2\),也就是 \(T_1'<T_2'\)。Q.E.D.
那么依据这个结论,我们可以找到每一个序列右移后得到的序列,那么按这个顺序遍历,输出每一个序列的第一个元素即可。
代码
#include<bits/stdc++.h>
#define inf 0x3f3f3f3f
#define Inf (1ll<<60)
#define For(i,s,t) for(int i=s;i<=t;++i)
#define Down(i,s,t) for(int i=s;i>=t;--i)
#define ls (i<<1)
#define rs (i<<1|1)
#define bmod(x) ((x)>=p?(x)-p:(x))
#define lowbit(x) ((x)&(-(x)))
#define End {printf("NO\n");exit(0);}
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
inline void ckmx(int &x,int y){x=(x>y)?x:y;}
inline void ckmn(int &x,int y){x=(x<y)?x:y;}
inline void ckmx(ll &x,ll y){x=(x>y)?x:y;}
inline void ckmn(ll &x,ll y){x=(x<y)?x:y;}
inline int min(int x,int y){return x<y?x:y;}
inline int max(int x,int y){return x>y?x:y;}
inline ll min(ll x,ll y){return x<y?x:y;}
inline ll max(ll x,ll y){return x>y?x:y;}
char buf[1<<20],*p1,*p2;
#define gc() (p1 == p2 ? (p2 = buf + fread(p1 = buf, 1, 1 << 20, stdin), p1 == p2 ? EOF : *p1++) : *p1++)
#define read() ({\int x = 0, f = 1;\char c = gc();\while(c < '0' || c > '9') f = (c == '-') ? -1 : 1, c = gc();\while(c >= '0' && c <= '9') x = x * 10 + (c & 15), c = gc();\f * x;\
})
void write(int x){if(x>=10) write(x/10);putchar(x%10+'0');
}
const int N=10100,M=20;
int n,m,t[M],a[N],cnt,st[N];
void findst(){For(i,0,m) ct[i]=t[i];int ind=0;For(i,1,n){while(!ct[ind]) ++ind;st[i]=ind;--ct[ind];}
}
vector<int> nod[M];
int cur[M],to[N];
int main()
{
#if !ONLINE_JUDGEfreopen("permutation.in","r",stdin);freopen("permutation.out","w",stdout);
#endif n=read(),m=read();int mn=m;For(i,1,n) a[i]=read(),++t[a[i]],ckmn(mn,a[i]);findst();For(i,1,n) nod[st[i]].push_back(i);For(i,1,n){to[nod[a[i]][cur[a[i]]]]=i;++cur[a[i]];}int nw=1;For(i,1,n){printf("%d ",st[nw]);nw=to[nw];}return 0;
}