[JZOJ5772]【NOIP2008模拟】今天你AK了吗?
直接模拟...不知道为什么讲的这么玄学。
其实是显然的事。
对于从左到右的位置i,前面有(n-1)!种可能...
于是就把剩下的数字中第k / (n - 1)!个数选到当前位置, 然后k %= (n - 1)!,
然后对于后面也是这样。。。
要写高精不开心,直接弃疗,手懒,我是不会写高精的233.
复杂度是O(N^2)的过不去,听讲解的什么奇怪算法不太明白为什么要这么做。
直接用树状数组维护, 再套二分找第k个数就ok了。
复杂度O(Nlog^2N)。
考场上O(N^2)能过不写高精的数据,于是弃疗了没写树状数组套二分。
放上考场60分代码
#include <iostream> #include <cstdio> #include <cstring> #include <string> #include <queue> #include <vector> #include <algorithm> using namespace std; inline int read() { int res=0;char c=getchar();bool f=0; while(!isdigit(c)) {if(c=='-')f=1;c=getchar();} while(isdigit(c))res=(res<<3)+(res<<1)+(c^48),c=getchar(); return f?-res:res; } #define ll long long int n; unsigned ll k; int wei[200005]; unsigned ll fac[1000005]; bool vis[1000005]; int main() { freopen("array.in", "r", stdin); freopen("array.out", "w", stdout); n = read(); fac[1] = 1; for (int i = 2 ; i <= n ; i ++) fac[i] = fac[i-1] * i; cin >> k; k--; for (register int i = 1 ; i < n ; i ++) { int re,sum = 0; for (register int j = 1 ; j <= n; j ++) { if (sum == k / fac[n-i] + 1) break; if (!vis[j]) re = j, sum++; } printf("%d ", re); vis[re] = 1; k %= fac[n-i]; } for (register int i = 1 ; i <= n ; i ++) if (!vis[i]) return printf("%d", i), 0; return 0; }