permutation 1【HDU-6628】【排列组合+线段树】
2019-08-05 19:29
288 查看
这次是杭电多校的第五场了,时间也已经到了一半的时候,但是,这场打的很糟糕了。
这道题我比赛的时候,一直再想办法完善我的思维, 我手玩了几组样例,2、3、4,然后找到了个看似很成立的规律就是我们可以固定前两个数,后面的N-2个数就是按照阶乘的某种关系,我们可以就寻访第K小,然后推下去,想想,no problem!开始!然后WA,一直WA…… QAQ,然后最后一发略改了精度再交,比赛已经结束了。
下来之后想到这样一组可以推翻我自己的样例:
[code]1 5 25
true answer:5 3 4 1 2
my answer:4 2 1 3 5
是因为,我根据"(N-2) ! "来确定了位置,但是实际上并不是这样来确定的!
Wrong Code:
[code]#include <iostream> #include <cstdio> #include <cmath> #include <string> #include <cstring> #include <algorithm> #include <limits> #include <vector> #include <stack> #include <queue> #include <set> #include <map> #define lowbit(x) ( x&(-x) ) #define pi 3.141592653589793 #define e 2.718281828459045 #define INF 0x3f3f3f3f #define HalF (l + r)>>1 #define lsn rt<<1 #define rsn rt<<1|1 #define Lson lsn, l, mid #define Rson rsn, mid+1, r #define QL Lson, ql, qr #define QR Rson, ql, qr #define myself rt, l, r using namespace std; typedef long long ll; const int maxN = 25; int N; ll K, jiecheng[maxN], pre_sum[105]; int tree[maxN<<2]; void buildTree(int rt, int l, int r) { tree[rt] = 1; if(l == r) return; int mid = (l + r)>>1; buildTree(rt<<1, l, mid); buildTree(rt<<1|1, mid + 1, r); tree[rt] = tree[rt<<1] + tree[rt<<1|1]; } int query(int rt, int l, int r, int kth) { if(l == r) return l; int mid = (l + r)>>1; if(tree[rt<<1] >= kth) return query(rt<<1, l, mid, kth); else return query(rt<<1|1, mid + 1, r, kth - tree[rt<<1]); } void update(int rt, int l, int r, int qx) { tree[rt]--; if(l == r) return; int mid = (l + r)>>1; if(qx <= mid) update(rt<<1, l, mid, qx); else update(rt<<1|1, mid + 1, r, qx); } int main() { int T; scanf("%d", &T); jiecheng[0] = 1; jiecheng[1] = 1; for(ll i=2; i<=20; i++) jiecheng[i] = jiecheng[i - 1] * i; pre_sum[0] = 0; while(T--) { scanf("%d%lld", &N, &K); buildTree(1, 1, N); for(int i=1; i<=N-1; i++) pre_sum[i] = pre_sum[i-1] + i; for(int i=1; i<=N-1; i++) pre_sum[i + N - 1] = pre_sum[i + N - 2] + N - i; ll Big_pos = K / jiecheng[N - 2] + (K % jiecheng[N - 2] == 0 ? 0 : 1); //大区间 int pos = (int)(lower_bound(pre_sum + 1, pre_sum + 2 * N - 2, Big_pos) - pre_sum); K -= pre_sum[pos - 1] * jiecheng[N - 2]; int rang_len; if(pos < N) rang_len = N - pos; else rang_len = pos - N + 1; ll small_pos = K / jiecheng[N - 2]; if(small_pos * jiecheng[N-2] == K) small_pos --; small_pos++; K -= (small_pos - 1) * jiecheng[N-2]; int a = N - (int)small_pos + 1, b = a - rang_len; if(pos < N) printf("%d %d", a, b); else printf("%d %d", b, a); update(1, 1, N, a); update(1, 1, N, b); for(int i=N-3; i>=0; i--) { int tmp = K / jiecheng[i] - (K % jiecheng[i] == 0 ? 1 : 0), now; //tmp = min(tmp, tree[1] - 1); printf(" %d", (now = query(1, 1, N, tmp + 1))); update(1, 1, N, now); if(K > tmp * jiecheng[i]) K -= tmp * jiecheng[i]; } printf("\n"); } return 0; }
现在,我要做的是,去把这道题改正回来,我们看到这里的K只有最大1e4,也知道8!= 40320就是大于1e4了,所以,我们不妨从这个角度出发来思考这个问题。
loading……
接下去,我发现我的这样的写法只局限于固定前两个数的时候,并且恒定成立那么,我们是不是可以对其余的进行直接暴力排序即可,因为在这里,我们要让"(N - 2) ! ≥ 1e4",所以,N需要>9,也就是N从10开始的所有的答案都是可以符合我上面的代码的思维的,接下去我们只需要去暴力一个预处理"≤9"的所有的数的这样的第K小的状态即可。
Accept Code:
[code]#include <iostream> #include <cstdio> #include <cmath> #include <string> #include <cstring> #include <algorithm> #include <limits> #include <vector> #include <stack> #include <queue> #include <set> #include <map> #define lowbit(x) ( x&(-x) ) #define pi 3.141592653589793 #define e 2.718281828459045 #define INF 0x3f3f3f3f #define HalF (l + r)>>1 #define lsn rt<<1 #define rsn rt<<1|1 #define Lson lsn, l, mid #define Rson rsn, mid+1, r #define QL Lson, ql, qr #define QR Rson, ql, qr #define myself rt, l, r using namespace std; typedef unsigned long long ull; typedef long long ll; const int maxN = 25; bool vis[maxN]; int N, K, tot, arr[maxN], pre[10][10005][10], ans[maxN]; struct node { int a[maxN], len, d[maxN]; friend bool operator < (node e1, node e2) { for(int i=1; i<e1.len; i++) { if(e1.d[i] < e2.d[i]) return true; else if(e1.d[i] > e2.d[i]) return false; } return false; } }a[362885]; ll jiecheng[maxN]; void dfs(int now, int depth) { if(now == depth) { ++tot; for(int i=1; i<now; i++) a[tot].d[i] = arr[i+1] - arr[i]; for(int i=1; i<=now; i++) a[tot].a[i] = arr[i]; a[tot].len = depth; return; } for(int i=1; i<=depth; i++) { if(!vis[i]) { vis[i] = true; arr[now + 1] = i; dfs(now + 1, depth); vis[i] = false; } } } inline void pre_did() { jiecheng[0] = jiecheng[1] = 1; for(int i=2; i<=20; i++) jiecheng[i] = jiecheng[i-1] * i; for(int i=2; i<=9; i++) { memset(vis, false, sizeof(vis)); tot = 0; dfs(0, i); sort(a + 1, a + tot + 1); int _UP = min(10000, tot); for(int j=1; j<=_UP; j++) //第几小 { for(int k=1; k<=i; k++) { pre[i][j][k] = a[j].a[k]; } } } } int tree[maxN<<2]; void buildTree(int rt, int l, int r) { tree[rt] = 1; if(l == r) return; int mid = (l + r)>>1; buildTree(rt<<1, l, mid); buildTree(rt<<1|1, mid + 1, r); tree[rt] = tree[rt<<1] + tree[rt<<1|1]; } int query(int rt, int l, int r, int kth) { if(l == r) return l; int mid = (l + r)>>1; if(tree[rt<<1] >= kth) return query(rt<<1, l, mid, kth); else return query(rt<<1|1, mid + 1, r, kth - tree[rt<<1]); } void update(int rt, int l, int r, int qx) { tree[rt]--; if(l == r) return; int mid = (l + r)>>1; if(qx <= mid) update(rt<<1, l, mid, qx); else update(rt<<1|1, mid + 1, r, qx); } int pre_sum[maxN<<1]; int main() { int T; scanf("%d", &T); pre_did(); while(T--) { scanf("%d%d", &N, &K); if(N > 9) { ans[1] = N; ans[2] = 1; memset(vis, false, sizeof(vis)); vis[1] = vis = true; printf("%d %d", N, 1); buildTree(1, 1, N); update(1, 1, N, 1); update(1, 1, N, N); for(int i=1; i<=N-1; i++) pre_sum[i] = pre_sum[i-1] + i; for(int i=1; i<=N-1; i++) pre_sum[i + N - 1] = pre_sum[i + N - 2] + N - i; ll Big_pos = K / jiecheng[N - 2] + (K % jiecheng[N - 2] == 0 ? 0 : 1); //大区间 int pos = (int)(lower_bound(pre_sum + 1, pre_sum + 2 * N - 2, Big_pos) - pre_sum); K -= pre_sum[pos - 1] * jiecheng[N - 2]; int rang_len; if(pos < N) rang_len = N - pos; else rang_len = pos - N + 1; ll small_pos = K / jiecheng[N - 2]; if(small_pos * jiecheng[N-2] == K) small_pos --; small_pos++; K -= (small_pos - 1) * jiecheng[N-2]; for(int i=N-3; i>=0; i--) { int tmp = K / jiecheng[i] - (K % jiecheng[i] == 0 ? 1 : 0), now; //tmp = min(tmp, tree[1] - 1); printf(" %d", (now = query(1, 1, N, tmp + 1))); update(1, 1, N, now); if(K > tmp * jiecheng[i]) K -= tmp * jiecheng[i]; } printf("\n"); //for(int i=1; i<=N; i++) printf("%d%c", ans[i], i == N ? '\n' : ' '); } else { for(int i=1; i<=N; i++) printf("%d%c", pre [K][i], i == N ? '\n' : ' '); } } return 0; }
相关文章推荐
- HDU 5753 Permutation Bo 排列组合& 期望 多校3
- HDU 4372 Count the Buildings(组合数学-斯特林数,组合数学-排列组合)
- HDU 1521 排列组合
- hdu 1716 排列2 dfs 组合
- hdu 1015 Safecracker【dfs 排列组合】
- hdu1261 java水过高精度排列组合。。
- HDU 4006 POJ 2828 线段树(排列/找有序位置)
- Hdu 4465 Candy (快速排列组合+概率)
- HDU 1271整数对----排列组合
- HDU 4372 Count the Buildings(组合数学-斯特林数,组合数学-排列组合)
- [HDU 1521] 排列组合 指数型母函数
- HDU 4045 Machine scheduling (组合数学-斯特林数,组合数学-排列组合)
- HDU 6143 排列组合 - DP
- hdu 1521 排列组合 指数型母函数
- hdu 4451 Dressing 排列组合/水题
- 排列组合(HDU_1521) 指数型母函数
- hdu 1716 排列2(stl next_permutation)
- hdu 1027 Ignatius and the Princess II【dfs 排列组合】
- HDU 5151 Sit sit sit 区间DP + 排列组合
- hdu 2200 Eddy's AC难题 (排列组合 就是求(a+b)的n次方的展开式)