[AGC030F] Permutation and Minimum 题解
Permutation and Minimum
看到 300 的数据范围,再加上计数题,很容易就往计数 DP 方向去想。
为方便,我们将
因为是两个位置取
考虑当前填入一个数。这个数有两种可能:一是与比它小的数匹配,此时最小值已经确定了,是那个更小的数,而更小数已经被填入序列,所以当前数与哪个比它小的数匹配根本不影响。二是与比它大的数匹配——此时最小值不确定,因此与不同的比它大的数在不同位置匹配会有不同结果。
于是我们便依次设出了剩余两维的意义:前
我们考虑分情况从
情形1. 若数
情形1.1. 若数
则此时显然其已被唯一确定,直接划归
情形1.2. 若数
有两种情形:其与比它小的东西匹配,或者与比它大的东西匹配。
情形1.2.1. 与比它小的东西匹配。
则依照定义,其应与
情形1.2.2. 与比它大的东西匹配。
则依照定义,其应划归
情形2. 若数
情形2.1. 作为
则此时与
情形2.2. 作为
则直接划归即可,因为方案数已在 1.2.1 中被计算。故
情形2.3. 作为
依照定义,
显然,总序列中,若我们设
显然转移
#include<bits/stdc++.h>
using namespace std;
const int mod=1e9+7;
const int N=610;
int n,a[N],p[N],f[2][N][N];
int sig[N],mat[N],sur[N];
int main(){
scanf("%d",&n);
n<<=1;
for(int i=1;i<=n;i++) mat[i]=((i-1)^1)+1;
for(int i=1;i<=n;i++) scanf("%d",&a[i]),p[a[i]]=i;
for(int i=1;i<=n;i++) if(a[i]!=-1&&a[mat[i]]==-1) sig[a[i]-1]++;
for(int i=n;i>=0;i--) sig[i]+=sig[i+1];
for(int i=1;i<=n;i++) if(a[i]!=-1&&a[mat[i]]!=-1) sur[a[i]-1]++;
for(int i=n;i>=0;i--) sur[i]+=sur[i+1];
f[0][0][0]=1;
for(int i=0;i<n;i++){
memset(f[!(i&1)],0,sizeof(f[!(i&1)]));
for(int j=0;j<=i;j++){
for(int k=0;j+k<=i;k++){
if(n-(j+sur[i])-k*2-sig[i]*2<0)continue;
if(!f[i&1][j][k])continue;
if(p[i+1]){
if(a[mat[p[i+1]]]!=-1){f[!(i&1)][j+1][k]=f[i&1][j][k];continue;}
(f[!(i&1)][j][k+1]+=f[i&1][j][k])%=mod;
(f[!(i&1)][j+2][k]+=1ll*(i-j-k)*f[i&1][j][k]%mod)%=mod;
}else{
if(k)(f[!(i&1)][j+2][k-1]+=f[i&1][j][k])%=mod;
(f[!(i&1)][j][k]+=f[i&1][j][k])%=mod;
(f[!(i&1)][j][k+1]+=1ll*(n-(j+sur[i])-k*2-sig[i]*2)/2*f[i&1][j][k]%mod)%=mod;
}
}
}
}
printf("%d\n",f[n&1][n][0]);
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通