zoukankan      html  css  js  c++  java
  • 题解 [AGC030F] Permutation and Minimum

    我们把位置在((2i - 1, 2i))的两个点叫做一对点。

    显然如果这对点两个都被限定了直接丢掉完事。

    如果有一个没有被限定就先留下来。

    注意到其他的形如((-1, -1))的顺序是可以随便变化的, 所以先不考虑, 最后乘上一个阶乘就可以了。

    考虑用(f(i, j, k))表示当前填第(i)个数, 剩下(j)((-1, d))对, 这种对是自己搞出来的, 还剩下(k)((-1, e))对, 是被限定了的。

    从这里可以发现, 我们的(i)应该从大到小枚举, 这样才可以避免后效性, 否则前面选了一个数, 后面就没法改变这一对的值, 从而出现后效性。

    然后就直接分类讨论(dp)就好了。

    #include <cmath>
    #include <cstdio>
    #include <vector>
    #include <cstring>
    #include <algorithm>
    #include <iostream>
    
    using namespace std;
    
    #define R register
    const int N = 600 + 5;
    const int P = 1e9 + 7;
    
    inline int read() {
    	int x = 0, f = 1; char a = getchar();
    	for(; a > '9' || a < '0'; a = getchar()) if(a == '-') f = -1;
    	for(; a >= '0' && a <= '9'; a = getchar()) x = x * 10 + a - '0';
    	return x * f;
    }
    
    int n;
    int a[N], ok[N], vis[N];
    int f[N][N][N];
    int S[N];
    int tot1 = 0, tot2 = 0;
    
    int main() {
    	#ifdef IN
    	freopen("a.in", "r", stdin);
    	//freopen(".out", "w", stdout);
    	#endif
    	n = read(); n <<= 1;
    	for(R int i = 1; i <= n; i ++) a[i] = read();
    	for(R int i = 1; i <= n; i += 2) {
    		if(a[i] > 0 && a[i + 1] > 0) {
    			vis[a[i]] = 1;
    			vis[a[i + 1]] = 1;
    			continue;
    		}
    		else {
    			if(a[i] == -1 && a[i + 1] == -1) tot1 ++;
    			else {
    				tot2 ++;
    				if(a[i + 1] == -1) ok[a[i]] = 1;
    				else ok[a[i + 1]] = 1; 		
    			}
    		}
    	}
    	int m = 0;
    	for(R int i = n; i >= 1; i --) if(vis[i] == 0) S[++ m] = i;
    	f[0][0][0] = 1;
    	for(R int i = 1; i <= m; i ++) 
    		for(R int j = 0; j <= n; j ++)
    			for(R int k = 0; k <= n; k ++) {
    				if(! ok[S[i]]) {
    					if(j) f[i][j][k] = (f[i][j][k] + f[i - 1][j - 1][k]) % P;
    					f[i][j][k] = (f[i][j][k] + f[i - 1][j + 1][k]) % P;
    					f[i][j][k] = (f[i][j][k] + 1LL * f[i - 1][j][k + 1] * (k + 1) % P) % P;
    				}
    				else {
    					f[i][j][k + 1] = (f[i][j][k + 1] + f[i - 1][j][k]) % P;
    					if(j) f[i][j - 1][k] = (f[i][j - 1][k] + f[i - 1][j][k]) % P;
    				}
    			}
    	int ans = f[m][0][0];
    	for(R int i = 1; i <= tot1; i ++) ans = 1LL * ans * i % P;
    	printf("%d
    ", ans);
    	return 0;
    }
    
  • 相关阅读:
    springboot 入门
    json-lib 的 maven dependency 引入及Jar包下载
    DataGridView 使用技巧精华
    SqlServer无备份下误删数据恢复
    Reflector 已经out了,试试ILSpy
    C# 反射,动态编译
    windows8和windows server2012不联网安装.net 3.5(包括2.0和3.0)
    如何附加被分离的质疑数据库? [转]
    easyui validatebox 验证类型
    所见即所得:七大无需编程的DIY开发工具
  • 原文地址:https://www.cnblogs.com/clover4/p/13813652.html
Copyright © 2011-2022 走看看