【网页链接】
https://www.luogu.com.cn/problem/P3014
【题解】
康托展开板子题
树状数组优化
康托展开可以用来hash,压缩状态,比如八数码问题,把一种排列表示成一个整数
同时,排列方式和整数的映射是可逆的。
【代码】
#include <bits/stdc++.h>
using namespace std;
#define lowbit(x) (x&-x)
#define ll long long
const int maxn = 25;
ll n,k,A[maxn];
ll tree[maxn],fac[maxn];
bool vis[maxn];
void add(ll x,ll y)
{
for(ll i = x;i<=n;i+=lowbit(i))
tree[i]+=y;
}
ll query(ll x)
{
ll ret = 0;
for(ll i = x;i;i-=lowbit(i))
ret+=tree[i];
return ret;
}
int main()
{ ll ans;
char c;
scanf("%lld%lld",&n,&k);
fac[0] = 1;
for(int i=1;i<n;i++)
fac[i] = fac[i-1]*i;
for(int j=1;j<=k;j++)
{
cin >> c;
memset(vis,0,sizeof(vis));
memset(tree,0,sizeof(tree));
for(int i=1;i<=n;i++)
add(i,1);
if(c == 'P')
{
scanf("%lld",&A[0]);
A[0]--;
for(int i=1;i<=n;i++)
{ ll tmp = A[0]/fac[n-i];
for(int k = 1;k<=n;k++)
{
if(vis[k]) continue;
if(!tmp)
{
printf("%lld ",k);
vis[k] = 1;
break;
}
tmp--;
}
A[0]%=fac[n-i];
}
cout << endl;
}
else//康托展开
{ ans = 0;
for(int i=1;i<=n;i++)
{ scanf("%lld",&A[i]);
add(A[i],-1);
ans+=query(A[i])*fac[n-i];
}
printf("%lld\n",ans+1);
}
}
return 0;
}