题解:P5972 [PA 2019] Desant
masterhuang · · 题解
给定一个
1 到n 的排列a_1,a_2,\cdots ,a_n ,它有2^n-1 个非空子序列。请对于每个
k ,找到一个长度为k 的子序列,使得这个子序列的逆序对数量最少,并输出逆序对数量最少的子序列的数量。
- 依然是状态压缩的思想,注意到很多状态是等价的。
考虑从前往后 DP,暴力是记录
但我们注意到,设
于是状态数不会超过每段长度
于是直接 DP 就可以了。时间复杂度是 map 或许会被卡常, 手写哈希表可以稳过。
变进制状态存储(虽然我觉得你们都会)
考虑第一位
记 map。
于是这题,对于每个
类似题目:CF1552G,P10360
代码:
#include<bits/stdc++.h>
#define LL long long
#define P pair<int,LL>
#define fr(x) freopen(#x".in","r",stdin);freopen(#x".out","w",stdout);
using namespace std;
const int N=45;
int n,a[N],c[N][N],ml[N][N],d[N],C[N],o[N];
vector<P>f,g;
inline void upd(P &x,P y){
auto& [u,v]=x;auto [p,q]=y;
if(p<u) x=y;else if(p==u) v+=q;
}
int main()
{
ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);cin>>n;
for(int i=1;i<=n;i++) cin>>a[i];
for(int i=0;i<=n;i++)
{
for(int j=i+1;j<=n;j++) c[i][++d[i]]=a[j];
sort(c[i]+1,c[i]+1+d[i]);c[i][++d[i]]=n+1;int s=1;
for(int j=1;j<=d[i];j++) ml[i][j]=s,s*=c[i][j]-c[i][j-1];
ml[i][d[i]+1]=s;
}f={{0,1}};
for(int i=1;i<=n;i++)
{
g=vector<P>(ml[i][d[i]+1],{999,0});
int w=find(c[i-1],c[i-1]+n+1,a[i])-c[i-1];int S=0;
for(auto [u,v]:f)
{
for(int j=d[i-1],x=S;j;j--) o[j]=x/ml[i-1][j],x%=ml[i-1][j];
fill(C,C+d[i]+1,0);int ad=0;
for(int j=1;j<=w;j++) C[j]=o[j];
for(int j=w+1;j<=d[i-1];j++) C[j-1]+=o[j],ad+=o[j];
auto calc=[&](){
int s=0;
for(int j=1;j<=d[i];j++) s+=ml[i][j]*C[j];
return s;
};
upd(g[calc()],{u,v});C[w]++;
upd(g[calc()],{u+ad,v});S++;
}swap(f,g);
}
for(int i=1;i<=n;i++) cout<<f[i].first<<" "<<f[i].second<<"\n";
return 0;
}