康拓展开利用了字典序的关系,其实就是一个暴力的思路和排列组合的知识,把一个序列离散化城几个数字,这样对一种情况的记录,或者是状态的转移更加方便,高效
如果对于空间有要求,开不下树状数组的话,可以考虑直接有cantor展开的暴力写法
暴力代码
inline ll contor(ll t[])
{
ll base=1;f[0]=1;
for(ll i=1;i<=n;i++) f[i]=(f[i-1]*i)%mod;
ll s=1;
for(int i=1;i<n;i++)
{
ll tmp=0;
for(int j=i+1;j<=n;j++)
{
if(t[j]<t[i])
{
tmp++;
}
}
s=(s+tmp*(f[n-i]%mod))%mod;
}
return s%mod;
}
int main()
{
n=read();
for(int i=1;i<=n;i++)
{
scanf("%lld",&a[i]);
}
printf("%lld",contor(a));
return 0;
}
如果只追求速度,对空间没有限制的话,就可以用树状数组对查询在一个数后面,比他小的数字有几个的时候,可以利用,把时间复杂度从O(n)下降到O(log(n)),这样的优化还是不错的
优化过后的时间会比于原来快上十几倍吧
树状数组的优化
ll n,ans;
ll funtionat[Maxn]={1,1},a[Maxn],tre[Maxn];;
inline void update(int x,int k)
{
for(;x<=n;x+=(x&-x)) tre[x]+=k;
}
inline int query(int x)
{
int t=0;
for(;x;x-=(x&-x)) t+=tre[x];
return t;
}
int main()
{
n=read();
for(int i=1;i<=n;i++)
{
funtionat[i]=(funtionat[i-1]*i)%mod;
update(i,1);
}
for(int i=1;i<=n;i++)
{
a[i]=read();
ans=(ans+(query(a[i]-1))*funtionat[n-i]%mod)%mod;
update(a[i],-1);
}
printf("%lld",ans+1);
return 0;
}
不要在数组名称为甚那么长