• P3182 [HAOI2016]放棋子 错排问题


    题目描述

    给你一个N*N的矩阵,每行有一个障碍,数据保证任意两个障碍不在同一行,任意两个障碍不在同一列,要求你在这个矩阵上放N枚棋子(障碍的位置不能放棋子),要求你放N个棋子也满足每行只有一枚棋子,每列只有一枚棋子的限制,求有多少种方案。

    输入输出格式

    输入格式:

    第一行一个N,接下来一个N*N的矩阵。N<=200,0表示没有障碍,1表示有障碍,输入格式参考样例

    输出格式:

    一个整数,即合法的方案数。

    输入输出样例

    输入样例#1: 复制
    2
    0 1
    1 0
    输出样例#1: 复制
    1




    错排问题
    错排的种数
    公式:D(n)=(n1)(D(n2)+D(n1))
    特殊地,D(1) = 0, D(2) = 1D(1)=0,D(2)=1.

    我们可以观察发现,每一行的障碍位置对答案并没有影响。

    于是我们可以将此时的矩阵化成如下形式:

    1 0 0 0
    0 1 0 0
    0 0 1 0
    0 0 0 1

    此时障碍列的排列为: 1 2 3 4 于是我们问题可以转化为: 从每行中选出一个1~n1 n的没出现的书且和障碍不相同

    即:问一个1~n1 n的数列的排列与原数列的位置都不相同的个数

    所以这就是一个错位排序了,但是为了让代码量变大,便没有模数,所以要打高进度

    #include<cstdio>
    using namespace std;
    // D(n)=(n-1)*(D(n-1)+D(n-2))
    // D(1)=0 D(2)=1
    
    int n;
    int D[205][100005];
    
    void ad(int now){
        int x=0;
        for(int i=1;i<100005;i++){
            D[now][i]=D[now-1][i]+D[now-2][i]+x;
            x=D[now][i]/10;
            D[now][i]%=10;
        }
        x=0;
        for(int i=1;i<100005;i++){
            D[now][i]=D[now][i]*(now-1)+x;
            x=D[now][i]/10;
            D[now][i]%=10;
        }
    }
    
    signed main(){
        scanf("%d",&n);
        D[2][1]=1;
        if(n==1||n==2){
            printf("%d",n-1);
            return 0;
        }
        for(int i=3;i<=n;i++)
            ad(i);
        int lenc=100004;
        while(D[n][lenc]==0) lenc--;
        while(lenc) printf("%d",D[n][lenc--]);
        return 0;
    } 
    View Code










  • 相关阅读:
    浏览器的垃圾回收机制
    vue-router传参数的方式
    Vue插槽
    自定义事件
    vue计算属性和监听器
    vue绑定样式
    循环中使用同步请求
    小白之路 | 从小学一年级期末考试看servlet+jsp技术
    Java实现简单计算器的探索性做法
    分布式数据库NoSQL简介
  • 原文地址:https://www.cnblogs.com/bxd123/p/10832384.html
Copyright © 2020-2023  润新知