康拓展开
正向展开普通解法
将一个字典序排列转换成序号。例如:12345->1,12354->2。
int f[20];
void jie_cheng(int n) { // 打出1-n的阶乘表f[0] = f[1] = 1; // 0的阶乘为1for (int i = 2; i <= n; i++) f[i] = f[i - 1] * i;
}
string str;
int kangtuo() {int ans = 1; // 注意,因为 12345 是算作0开始计算的,最后结果要把12345看作是第一个int len = str.length();for (int i = 0; i < len; i++) {int tmp = 0; // 用来计数的// 计算str[i]是第几大的数,或者说计算有几个比他小的数for (int j = i + 1; j < len; j++)if (str[i] > str[j]) tmp++;ans += tmp * f[len - i - 1];}return ans;
}
int main() {jie_cheng(10);string str = "52413";cout << kangtuo() << endl;
}
正向展开树状数组解
给定一个全排列,求出它是 1 ~ \(n\) 所有全排列的第几个,答案对 \(998244353\) 取模。
答案就是 \(\sum_{i = 1}^{n} res_{a_i} (n - i)!\) 。\(res_x\) 表示剩下的比 \(x\) 小的数字的数量,通过树状数组处理。
#include <bits/stdc++.h>
using namespace std;
#define LL long long
const int mod = 998244353, N = 1e6 + 10;
LL fact[N];
struct fwt{LL n;vector <LL> a;fwt(LL n) : n(n), a(n + 1) {}LL sum(LL x){LL res = 0;for (; x; x -= x & -x)res += a[x];return res;}void add(LL x, LL k){for (; x <= n; x += x & -x)a[x] += k;}LL query(LL x, LL y){return sum(y) - sum(x - 1);}
};
int main(){ios::sync_with_stdio(false);cin.tie(0);LL n;cin >> n;fwt a(n);fact[0] = 1;for (int i = 1; i <= n; i ++ ){fact[i] = fact[i - 1] * i % mod;a.add(i, 1);}LL ans = 0;for (int i = 1; i <= n; i ++ ){LL x;cin >> x;ans = (ans + a.query(1, x - 1) * fact[n - i] % mod ) % mod;a.add(x, -1);}cout << (ans + 1) % mod << "\n";return 0;
}
逆向还原
string str;
int kangtuo(){int ans = 1; //注意,因为 12345 是算作0开始计算的,最后结果要把12345看作是第一个int len = str.length();for(int i = 0; i < len; i++){int tmp = 0;//用来计数的for(int j = i + 1; j < len; j++){if(str[i] > str[j]) tmp++;//计算str[i]是第几大的数,或者说计算有几个比他小的数}ans += tmp * f[len - i - 1];}return ans;
}
int main(){jie_cheng(10);string str = "52413";cout<<kangtuo()<<endl;
}