AT4515 [AGC030F] Permutation and Minimum

https://www.luogu.com.cn/problem/AT4515

肯定是先配对

把相邻的两个 分为几类

  • ( a [ i ] , a [ i + 1 ] ) (a[i],a[i+1]) (a[i],a[i+1])两个都确定了,直接扔掉
  • ( − 1 , − 1 ) (-1,-1) (1,1)记作第一类
  • ( − 1 , a [ i + 1 ] ) (-1,a[i+1]) (1,a[i+1]) ( a [ i ] , − 1 ) (a[i],-1) (a[i],1)记作第二类

然后从大到小填数,这样能保证每类只会在小的那个被计算,不重复不漏,没有后效性

然后我们来设状态

f [ i ] [ j ] [ k ] f[i][j][k] f[i][j][k]表示从大到小填了前 i i i个,有 j j j个第一类已经填了一个即 ( − 1 , x ) (-1,x) (1,x),有 k k k个第二类

前不考虑 ( − 1 , − 1 ) (-1,-1) (1,1)的顺序,后面乘上个阶乘即可
然后考虑转移

  • i i i是属于第二类中的一个数
    f [ i ] [ j ] [ k ] + = f [ i − 1 ] [ j + 1 ] [ k ] f[i][j][k]+=f[i-1][j+1][k] f[i][j][k]+=f[i1][j+1][k]和一个第一类匹配
    f [ i ] [ j ] [ k ] + = f [ i − 1 ] [ j ] [ k − 1 ] f[i][j][k]+=f[i-1][j][k-1] f[i][j][k]+=f[i1][j][k1]单独成一个第二类
  • i i i没出现过

f [ i ] [ j ] [ k ] + = f [ i − 1 ] [ j − 1 ] [ k ] f[i][j][k]+=f[i-1][j-1][k] f[i][j][k]+=f[i1][j1][k]单独成一个第一类
f [ i ] [ j ] [ k ] + = f [ i − 1 ] [ j + 1 ] [ k ] f[i][j][k]+=f[i-1][j+1][k] f[i][j][k]+=f[i1][j+1][k] 和一个第一类贴贴
f [ i ] [ j ] [ k ] + = f [ i − 1 ] [ j ] [ k + 1 ] ∗ ( k + 1 ) f[i][j][k]+=f[i-1][j][k+1]*(k+1) f[i][j][k]+=f[i1][j][k+1](k+1) 选一个第二类的贴贴

代码很简单

code:

#include<bits/stdc++.h>
#define N 605
#define ll long long
#define mod 1000000007
using namespace std;
int n, a[N], ok[N], vis[N], gs, m;
ll f[2][N][N];
int main() {
    scanf("%d", &n); n <<= 1;
    for(int i = 1; i <= n; i ++) scanf("%d", &a[i]);
    
    for(int i = 1; i <= n; i += 2) {
        if(min(a[i], a[i + 1]) != -1) vis[a[i]] = vis[a[i + 1]] = 1;
        else {
            if(max(a[i], a[i + 1]) == -1) ++ gs;
            else ok[max(a[i], a[i + 1])] = 1;
        }
    }
    
    for(int i = n; i >= 1; i --) if(!vis[i]) a[++ m] = i;
    f[0][0][0] = 1;
    int p = 1, q = 0;
    for(int i = 1; i <= m; i ++, swap(p, q)) 
        for(int j = 0; j <= n; j ++)
            for(int k = 0; k <= n; k ++) {
                f[p][j][k] = 0;
                if(!ok[a[i]]) {
                    if(j) f[p][j][k] += f[q][j - 1][k];
                    f[p][j][k] += f[q][j + 1][k];
                    f[p][j][k] += f[q][j][k + 1] * (k + 1);
                    f[p][j][k] %= mod;
                } else {
                    f[p][j][k] += f[q][j + 1][k];
                    if(k) f[p][j][k] += f[q][j][k - 1];
                    f[p][j][k] %= mod;
                }
            }
    ll ans = f[m&1][0][0];
    for(int i = 1; i <= gs; i ++) ans = ans * i % mod;
    printf("%lld", ans);
    return 0;
}
posted @ 2021-11-07 20:43  lahlah  阅读(32)  评论(0编辑  收藏  举报