题目大意
有一个长度为n的排列,但是有一些位置的数字还没有确定。你需要统计逆序对为
1≤n≤103,1≤K≤109
保证没有确定的位数m不超过
题目分析
既然没有确定的位数最多只有14,那么考虑meet in middle。
搜出后面位置填了什么,然后将其用随便一种方式存下来。
然后搜出前面的位置填的数,然后在前面存下来的那里找到对应于没有出现过的数的状态,瞎合并一下。
如果你各种细节实现得好一点,你是可以做到O(m!(m/2)!×m2)的。
代码实现
#include <algorithm>
#include <iostream>
#include <cstdio>
using namespace std;
typedef long long LL;
const int N=1005;
const int L=14;
const int C=N*L/2;
const int S=3500;
const int P=67;
const int A=1<<L;
int pre[N][N],suf[N][N],tot[N];
int per[N],rem[N],pos[N],p[N];
bool exist[N],used[N];
int f[S][C];
int id[A];
int n,K,cnt,l,cur;
LL ans;
int lowbit(int x){return x&-x;}
int bitcount(int s)
{
int ret=0;
for (;s;s-=lowbit(s)) ++ret;
return ret;
}
void prepare()
{
for (int i=1;i<=n;++i)
{
for (int j=1;j<=n;++j) pre[i][j]=pre[i-1][j];
if (per[i]) ++pre[i][per[i]];
}
for (int i=1;i<=n;++i)
for (int j=n;j>=1;--j)
pre[i][j]+=pre[i][j+1];
for (int i=n;i>=1;--i)
{
for (int j=1;j<=n;++j) suf[i][j]=suf[i+1][j];
if (per[i]) ++suf[i][per[i]];
}
for (int i=1;i<=n;++i)
for (int j=1;j<=n;++j)
suf[i][j]+=suf[i][j-1];
for (int i=1;i<=n;++i)
if (per[i]) cur+=pre[i][per[i]+1];
l=pos[0]/2;
for (int s=0;s<1<<pos[0];++s)
if (bitcount(s)==pos[0]-l)
id[s]=++cnt;
}
int tmp[20],rec[20];
void load(int curr)
{
int s=0;
for (int i=l+1;i<=pos[0];++i) s|=1<<p[i]-1;
int sid=id[s],ret=curr;
for (int i=l+1;i<=pos[0];++i) ret+=pre[pos[i]][rem[p[i]]+1]+suf[pos[i]][rem[p[i]]-1];
tmp[0]=0,rec[0]=0;
for (int i=1;i<=pos[0];++i)
if (!((s>>i-1)&1)) tmp[++tmp[0]]=rem[i];
else rec[++rec[0]]=rem[i];
sort(tmp+1,tmp+1+tmp[0]),sort(rec+1,rec+1+rec[0]);
for (int i=1,ptr=1;i<=rec[0];++i)
{
for (;ptr<=tmp[0]&&tmp[ptr]<rec[i];++ptr);
ret+=tmp[0]+1-ptr;
}
++f[sid][ret];
}
void dfs(int x,int curr)
{
if (x==pos[0]+1)
{
load(curr);
return;
}
int total=0;
for (int i=1;i<=rem[0];++i)
if (!used[i]) used[i]=1,p[x]=i,dfs(x+1,curr+x-l-1-total),used[i]=0;
else ++total;
}
void solve(int curr)
{
int s=0;
for (int i=1;i<=l;++i) s|=1<<p[i]-1;
int sid=id[((1<<pos[0])-1)^s],ret=curr;
for (int i=1;i<=l;++i) ret+=pre[pos[i]][rem[p[i]]+1]+suf[pos[i]][rem[p[i]]-1];
if (K-cur-ret>=0&&K-cur-ret<=n*(pos[0]-l)) ans+=f[sid][K-cur-ret];
}
void calc(int x,int curr)
{
if (x==l+1)
{
solve(curr);
return;
}
int total=0;
for (int i=1;i<=rem[0];++i)
if (!used[i]) used[i]=1,p[x]=i,calc(x+1,curr+x-1-total),used[i]=0;
else ++total;
}
int main()
{
freopen("sequence.in","r",stdin),freopen("sequence.out","w",stdout);
scanf("%d%d",&n,&K);
for (int i=1;i<=n;++i)
{
scanf("%d",&per[i]);
if (!per[i]) pos[++pos[0]]=i;
else exist[per[i]]=1;
}
for (int i=1;i<=n;++i) if (!exist[i]) rem[++rem[0]]=i;
prepare(),dfs(l+1,0),calc(1,0);
printf("%lld\n",ans);
fclose(stdin),fclose(stdout);
return 0;
}