[HAOI2016]放棋子

题意

Here

思考

看第一眼:状压dp,再看范围gg

第二眼:普通dp,貌似可以直接递推?

其实就是个很裸的错排问题,写个博客顺便复习下~

错排问题就是说一个 \(n\) 的排列,每个元素都满足 \(a[i] != i\),求方案数

记 \(f[n]\) 为 \(n\) 的错排方案数,我们可以考虑递推:

  1. 放第 \(n\) 个元素,有 \(n-1\) 种方法
  2. 假设第 \(n\) 个元素放在了 \(p\) 位置,那么放编号为 \(p\) 的元素:
    1. 放在 \(n\) 位置,对于剩下 \(n-2\) 个元素,就有 \(f[n-2]\) 种放法
    2. 不放在 \(n\) 位置,对于剩下 \(n-1\) 个元素,就有 \(f[n-1]\) 种放法

那么递推方程:

\[f[n] = (n-1)*(f[n-1]+f[n-2])\]

再说说这题为什么是错排问题,首先,我们发现每一个障碍具体在哪不会影响答案,行与行的互换也是不影响的,我们可以将每个棋盘都转变为一个 \(n*n\) 的对角线上不能放棋子的棋盘,所以这就是一个错排问题了~

代码

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
struct BIG{
    int S[10010], len;
    void givint(int x){
        memset(S, 0, sizeof(S)); len = 0;
        while(x){
            S[++len] = x % 10; x /= 10;
        }
    }
    void clearx(){ memset(S, 0, sizeof(S)); len = 0; }
    BIG operator + (const BIG &a) const{
        BIG ans; ans.clearx();
        for(int i=1; i<=10000; i++) ans.S[i] += a.S[i] + S[i];
        for(int i=1; i<=10000; i++) ans.S[i+1] += ans.S[i]/10, ans.S[i]%=10;
        ans.len = 10000; while(!ans.S[ans.len]) ans.len --;
        return ans;
    }
    BIG operator * (const BIG &a) const{
        BIG ans; ans.clearx();
        for(int i=1; i<=a.len; i++)
            for(int j=1; j<=len; j++) ans.S[i+j-1] += a.S[i] * S[j];
        for(int i=1; i<=10000; i++) ans.S[i+1] += ans.S[i]/10, ans.S[i]%=10;
        ans.len = 10000; while(!ans.S[ans.len]) ans.len --;
        return ans;
    }
    void print(){
        for(int i=len; i>=1; i--) cout<<S[i];
    }
}D[220];
int n;
int main(){
    D[1].givint(0), D[2].givint(1);
    cin >> n;
    for(int i=3; i<=n; i++){
        BIG tmp; tmp.givint(i - 1);
        D[i] = BIG(tmp * (D[i-1] + D[i-2]));
    }
    D[n].print();
    return 0;
}

总结

看出错排问题这题就很水了。(\(ps:\) 注意写高精度)

原文地址:https://www.cnblogs.com/alecli/p/9912354.html

时间: 2024-10-11 06:17:27

[HAOI2016]放棋子的相关文章

bzoj4563[Haoi2016]放棋子

bzoj4563[Haoi2016]放棋子 题意: 给你一个N*N的矩阵,每行有一个障碍,数据保证任意两个障碍不在同一行,任意两个障碍不在同一列.要求你放N枚棋子(障碍的位置不能放棋子),也满足每行只有一枚棋子,每列只有一枚棋子的限制,求有多少种方案.N≤200. 题解: 发现在障碍在什么位置和答案无关.因此可以把棋子摆成左上-右下对角线,然后就是错排问题(一个长度为n的排列,要求每个元素不能放在与自己编号相同的位置上,问有多少种方案满足条件)了.错排公式:f[i]=(f[i-1]+f[i-2]

[BZOJ 4563][Haoi2016]放棋子(错排公式)

Description 给你一个N*N的矩阵,每行有一个障碍,数据保证任意两个障碍不在同一行,任意两个障碍不在同一列,要求你在这个矩阵上放N枚棋子(障碍的位置不能放棋子),要求你放N个棋子也满足每行只有一枚棋子,每列只有一枚棋子的限制,求有多少种方案. Solution 其实和给出的障碍没什么关系,可以直接上错排公式(因为一开始的障碍可以看做一个排列,然后放棋子等同于要你生成一个新的不能有和原来位置相同元素的排列) f[n]=(f[n-1]+f[n-2])*(n-1)(为什么的话上一篇里有说Qw

bzoj4563【HAOI2016】放棋子

4563: [Haoi2016]放棋子 Time Limit: 10 Sec  Memory Limit: 128 MB Submit: 172  Solved: 119 [Submit][Status][Discuss] Description 给你一个N*N的矩阵,每行有一个障碍,数据保证任意两个障碍不在同一行,任意两个障碍不在同一列,要求你在 这个矩阵上放N枚棋子(障碍的位置不能放棋子),要求你放N个棋子也满足每行只有一枚棋子,每列只有一枚棋子 的限制,求有多少种方案. Input 第一行

LibreOJ #2061. 「HAOI2016」放棋子

二次连通门 : LibreOJ #2061. 「HAOI2016」放棋子 /* LibreOJ #2061. 「HAOI2016」放棋子 MDZZ ... 错排 + 高精 */ #include <iostream> #include <cstdio> #include <vector> #include <iomanip> #include <cassert> #include <algorithm> #define int64 l

BZOJ 3294: [Cqoi2011]放棋子

3294: [Cqoi2011]放棋子 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 628  Solved: 238[Submit][Status][Discuss] Description Input 输入第一行为两个整数n, m, c,即行数.列数和棋子的颜色数.第二行包含c个正整数,即每个颜色的棋子数.所有颜色的棋子总数保证不超过nm. Output 输出仅一行,即方案总数除以 1,000,000,009的余数. Sample Input

P3158 [CQOI2011]放棋子(dp+组合数)

P3158 [CQOI2011]放棋子 放棋子的顺序和方案数无关,所以可以从按颜色递推 设$f[u][p][k]$为放到第$u$种颜色,所剩空间$p*k$的方案数 $g[u][i][j]$表示第$u$种颜色占据$i*j$空间的方案数,可以预处理 $g[u][i][j]=\binom{i*j}{c[u]}-\sum_{p=1}^{i}\sum_{k=1}^{j}g[u][p][k]*\binom{i}{i-p}*\binom{j}{j-k}*[p<i||j<k]$ $f[u][p][k]=\su

[题解] [CQOI2011] 放棋子

题面 题解 为了练习计数而做 注意到一种颜色占据的行, 列其他的颜色不能放 又考虑到我们并不需要知道哪些行哪些列选了, 只需要知道还有几行几列没选即可 于是有 \(f[i][j][k]\) 代表前 \(i\) 种颜色选完之后, 还有 \(j\) 行没选, \(k\) 列没选的方案数 \(g[i][j][k]\) 代表, \(i\) 个棋子, 放在 \(j\) 行 \(k\) 列中并且没有空行空列的方案数 \(cnt_i\) 代表颜色为 \(i\) 的棋子有几个 有 \[ \displaystyl

dtoj1825. 放棋子(chess)

Sol 因为每种颜色的棋子互补影响,我们考虑f[i][j][k]表示前i种颜色,放了j行k列的方案数. 假设求出g[i][j][k]表示i个棋子占据恰好j行k列的方案数. 那么有f[i+1][j+x][k+y]=f[i][j][k]*g[a[i+1]][x][y]*C(n-j,x)*C(m-k,y); g的话我们用随便填的方案数C(x*y,i)-g[i][j][k]*C(x,i)*C(y,j) #include<cstdio> #include<iostream> #include

[CQOI2011] 放棋子 - 计数dp

在一个 \(m\) 行 \(n\) 列的棋盘里放一些彩色的棋子,使得每个格子最多放一个棋子,且不同颜色的棋子不能在同一行或者同一列,有多少种方法? Solution 设 \(f[i][j][k]\) 表示用前 \(k\) 种颜色的棋子,占领了 \(i\) 行 \(j\) 列的方案数 设 \(g[i][j][k]\) 表示用任意 \(k\) 个同色棋子占领 \(i\) 行 \(j\) 列的方案数,则考虑总方案数 - 实际上有没有被占领的行或列的方案数,则 \[g[i][j][k]=C_{ij}^k