ZOJ 3687 The Review Plan I ( 禁位排列 + 容斥原理 )

ZOJ 3687 The Review Plan I ( 禁位排列 + 容斥原理 )

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long LL;
#define CLR( a, b ) memset( a, b, sizeof(a) )
#define MOD 55566677
#define MAXN 55
LL fac[MAXN], res;
int n, m, row[MAXN], col[MAXN], g[MAXN][2], hash[MAXN][MAXN] ;

void init()
{
    fac[0] = 1;
    for( int i = 1; i < MAXN; ++i )
        fac[i] = ( fac[i-1] * i ) % MOD;
}

void dfs( int id, int num )
{
    if( id > m )
    {
        if( num & 1 )    res = ( ( res - fac[ n - num ] ) % MOD + MOD ) % MOD;
        else             res = ( res + fac[ n - num ] ) % MOD;
        return;
    }
    dfs( id + 1, num );
    if( row[g[id][0]] == 0 && col[g[id][1]] == 0 )
    {
        row[g[id][0]] = col[g[id][1]] = 1;
        dfs( id + 1, num + 1 );
        row[g[id][0]] = col[g[id][1]] = 0;
    }
}

int main()
{
    init();
    while( ~scanf( "%d %d", &n, &m ) )
    {
        CLR( row, 0 ), CLR( col, 0 ), CLR( hash, 0 );
        for( int i = 1; i <= m; ++i )
        {
            scanf( "%d %d", &g[i][0], &g[i][1] );
            if( hash[g[i][0]][g[i][1]] )
            {
                --i;
                --m;
            }
            else
                hash[g[i][0]][g[i][1]] = 1;
        }
        res = 0;
        dfs( 1, 0 );
        res = ( res % MOD + MOD ) % MOD;
        printf( "%lld\n", res );
    }
    return 0;
}

学习的暴搜

#include <cstdio>
#include <cstring>
typedef long long LL;
#define CLR( a, b ) memset( a, b, sizeof(a) )
#define MAXN 55
#define MOD 55566677
LL fac[ MAXN ], C[ MAXN][ MAXN ], r[ MAXN ], R[ MAXN ], res;
bool vis_r[ MAXN ], vis_c[ MAXN ], hash[ MAXN ][ MAXN ];
int n, m, h[ MAXN ], v[ MAXN ], one, x, y;

void init()    //递推初始化阶乘和组合数公式
{
    fac[0] = 1;
    for( int i = 1; i < MAXN; ++i )
        fac[i] = ( fac[i-1] * i ) % MOD;

    for( int i = 0; i < MAXN; ++i )
        C[i][i] = C[i][0] = 1;
    for( int i = 2; i < MAXN; ++i )
    {
        for( int j = 1; j < i; ++j )
        {
            C[i][j] = C[i - 1][j] + C[i - 1 ][j - 1];
            if( C[i][j] >= MOD )    C[i][j] -= MOD;
        }
    }
}

void dfs( int k, int id )
{
    if( k > n )
        return;
    for( int i = id; i < n; ++i )
    {
        for( int j = 0; j < n; ++j )
        {
            if( !vis_r[i] && !vis_c[j] && hash[i][j] )
            {
                r[k]++;
                if( r[k] >= MOD )    r[k] -= MOD;

                vis_r[i] = vis_c[j] = true;
                dfs( k + 1, i );
                vis_r[i] = vis_c[j] = false;
            }
        }
    }
} 

void cal()
{
    CLR( R, 0 );
    R[0] = 1;
    R[1] = m;
    for( int i = 2; i <= n; ++i )
    {
        for( int j = 0; j <= one && j <= i; ++j )
        {
            R[i] += r[i - j] * C[one][j];
            R[i] %= MOD;
        }
    }
}

LL solve()
{
    LL ans = fac[n];
    LL k = -1;
    for( int i = 1; i <= n; ++i )
    {
        ans += k * fac[n-i] * R[i];
        k *= -1;
    }
    ans = ( ans % MOD + MOD ) % MOD;
    return ans;
}

int main()
{
    init();
    while( ~scanf( "%d %d", &n, &m ) )
    {
        CLR( h, 0 ); CLR( v, 0 );
        CLR( r, 0 ); CLR( hash, false );
        CLR( vis_r, false ); CLR( vis_c, false );
        for( int i = 0; i < m; ++i )
        {
            scanf( "%d %d", &x, &y );
            x--;
            y--;
            if( hash[x][y] )
            {
                i--;
                m--;
                continue;
            }
            h[x]++;
            v[y]++;
            hash[x][y] = 1;
        }

        one = 0;
        for( int i = 0; i < n; ++i )
        {
            for( int j = 0; j < n; ++j )
            {
                if( hash[i][j] && ( h[i] <= 1 && v[j] <= 1 ) )
                {
                    hash[i][j] = false;
                    one++;
                }
            }
        }
        r[0] = 1;
        dfs( 1, 0 );
        cal();
        printf( "%lld\n", solve() );
    }
    return 0;
}

禁位排列

时间: 2024-10-14 04:51:30

ZOJ 3687 The Review Plan I ( 禁位排列 + 容斥原理 )的相关文章

zoj 3687 The Review Plan I 禁位排列 棋盘多项式

题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3687 题意:有N天和N个章节,每天可以完成一个章节,有M个限制,表示第Di天不能完成章节Ci. 问共有多少种计划方案可以完成所有章节. 思路: 学习了一下棋盘多项式的知识 http://wenku.baidu.com/link?url=NXPYih0AzZJTi0Tqd4Qb91vq2Rz0f3YCm7IQpu0pcbPTlv75DeiVtTj81sDtqdnv

zoj 3688 The Review Plan II 禁位排列 棋盘多项式 容斥

题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=4971 题意:共有N天和N个章节,每天完成一个章节,规定第i个章节不可以在第i天或者i+1天完成(第N个章节则是第N天和第1天不能),求分配能完成所有章节的方案数. 思路: 主要还是根据棋盘多项式的公式来求解: 但是这题和ZOJ3687不同,数据量N最大有100000,因此不能爆搜,需要推一下公式. 按照题意,先求禁位组成的棋盘的棋盘多项式,再用容斥.禁位组成的棋盘如

ZOJ 3687 The Review Plan I

The Review Plan I Time Limit: 5000ms Memory Limit: 65536KB This problem will be judged on ZJU. Original ID: 368764-bit integer IO format: %lld      Java class name: Main Michael takes the Discrete Mathematics course in this semester. Now it's close t

ZOJ 2688 The Review Plan II

https://zoj.pintia.cn/problem-sets/91827364500/problems/91827369470 题意: n天n个计划,一天完成一个计划,第i个计划不能在第i天和第i+1天完成,第n个计划不能在第n天和第1天完成,求安排计划的方案数. 有禁区的排列问题 在n*n有禁区棋盘上放n个棋子,每行每列只能放1个,第i行的禁区为第i和i+1列,第n行禁区为第n和1列 根据容斥原理,得 方案数=n! - r1(n-1)! + r2(n-2)! - …… ± rn 其中r

zoj 3812 We Need Medicine (dp 位优化 巧妙记录路径)

We Need Medicine Time Limit: 10 Seconds      Memory Limit: 65536 KB      Special Judge A terrible disease broke out! The disease was caused by a new type of virus, which will lead to lethal lymphoedema symptom. For convenience, it was namedLL virus.

ZOJ 3812 We Need Medicine 01背包+位优化

题目链接:点击打开链接 #include <cstdio> #include <algorithm> #include <iostream> #include <cstring> #include <map> typedef unsigned long long ll; using namespace std; const int N = 400 + 1; const int M = 200000 + 1; int t[N], w[N], g[5

ZOJ 3687

赤裸的带禁区的排列数,不过,难点在于如何用程序来写这个公式了.纠结了好久没想到,看了看别人的博客,用了DFS,实在妙极,比自己最初想用枚举的笨方法高明许多啊.\ http://blog.csdn.net/hlmfjkqaz/article/details/11037821 自己理解那个DFS后自己敲的.. #include <iostream> #include <cstdio> #include <cstring> #include <algorithm>

这个是置顶的标题(`?ω?&#180;)

寒假几天的集训来看,自己不会的算法还是很多_(:зゝ∠)_,还有一些暑假学的忘记了,想想整个大二上学期,也就学了一个网络流,一个AC自动机,一个后缀数组.寒假时间还是很充裕的,适合研究几个算法. 就目前来看,自己唯一有优势的地方是代码能力稍微好一些,其他很多地方还是不如别人... [下面的完整知识目录来自这里@whatbeg] 1: 高级数据结构(17) 并查集,线段树,树状数组,KMP,字典树(Trie),左偏树(可合并堆),单调队列,优先队列,AC自动机,后缀树/数组,二叉堆,伸展树,Tre

N皇后问题(位运算实现)

本文参考Matrix67的位运算相关的博文. 顺道列出Matrix67的位运算及其使用技巧 (一) (二) (三) (四),很不错的文章,非常值得一看. 主要就其中的N皇后问题,给出C++位运算实现版本以及注释分析. 皇后问题很经典,就不再赘述问题本身,解决皇后问题,一般采用的都是深搜DFS+回溯的方法,按照行(列)的顺序枚举每一个可以放置的情况,然后进行冲突判断,当前的放置是否合法,合法就继续搜索下一层,不合法就搜索就回溯.直到,找到一个合法的解,每一层都有一个皇后并且不发生冲突,这时候,放置