Codeforces题号:#340E

出处: Codeforces

主要算法:思维+DP

难度:4.8

题意:

有一个长度为$n$的排列(即各元素互不相同),其中有一些为-1。现要求将数填到这些-1上,使得原排列是一个错位排列。问有几种方法?

思路分析:

  又是一道超级难的DP……

  这不就是一个错排的模板题吗?不是只要看有几个-1就做多少的错排吗?确实,样例很不良心,那就给你一组反例吧……

  5

  -1 -1 2 3 -1

  我们注意到了,并不是剩下的元素全是错排。因为原来我们认为2不能处在2的位置,但是4作为第二个元素是可以处在2的位置的。这样一来……就错得很离谱了。

  但是这道题跟错排的关系依然是很大的。如果还不了解错排,可以参见我的另一篇博客「错位排列及有关例题」

    我们首先可以根据数字是否为-1,以及数字i是否被使用过,把给的数字$a[i]$分成几类:

    第一类,$a[i] = -1$ 且 数字$i$还没有被使用过(即数字$i$没有出现在给定的序列中),那么这个位置除了其位置本身对应的数字$i$以外,其他剩余的数字都可以填进来。

    第二类,$a[i] = -1$ 且 数字$i$已经被使用过了,那么任何剩余的数字都可以填进来而且不会影响错位排列,想填什么就填什么。

    第三类,$a[i] ≠ -1$ 且 数字$i$还没有被使用过,这种数字的个数应该和第一类相同,都是有限制的随便填。

    第四类,$a[i] ≠ -1$ 且 数字$i$已经被使用过了,这种东西用都没有,就当他们是垃圾就好了。

  首先我们可以统计出一类(或三类)数字的出现次数$y$,以及二类数字的出现次数$x$。我们只考虑二类数字可能组成的方案数,将有$x$个数字填到$x$个无限制的位置中,方案数就是$P_x^x$。

  下面正式开始DP。令$f[i]$表示加入$i$个一类数字后的方案数。因此很容易得到$f[0] = P_x^x,即 x!$

  下面开始状态转移。对于第$i$个一类数字,我们可以把他填入到无限制的二类数字的位置中,方案数是$x * f[i-1]$。剩余的就直接做错位排列即可。

代码注意点:

  随手MOD

Code

/*By QiXingzhi*/
#include <cstdio>
#include <queue>
#include <cstring>
#include <algorithm>
#define r read()
#define Max(a,b) (((a)>(b)) ? (a) : (b))
#define Min(a,b) (((a)<(b)) ? (a) : (b))
using namespace std;
typedef long long ll;
#define int ll
const int N = ;
const int INF = ;
const int MOD = ;
inline int read(){
int x = ; int w = ; register int c = getchar();
while(c ^ '-' && (c < '' || c > '')) c = getchar();
if(c == '-') w = -, c = getchar();
while(c >= '' && c <= '') x = (x << ) +(x << ) + c - '', c = getchar();
return x * w;
}
int n,ans,x,y;
int f[N],a[N],b[N];
inline int JieCheng(int x){
int res = ;
for(int i = ; i <= x; ++i){
res = (res * i) % MOD;
}
return res%MOD;
}
#undef int
int main(){
#define int ll
// freopen(".in","r",stdin);
n = r;
for(int i = ; i <= n; ++i){
a[i] = r;
if(a[i] != -){
b[a[i]] = ;
}
}
// for(int i = 1; i <= n; ++i){
// printf("%lld ",b[i]);
// }
for(int i = ; i <= n; ++i){
if(a[i] == - && b[i] > ){
++x;
}
// printf("a[%lld] = %lld b[%lld] = %lld\n",i,a[i],i,b[i]);
if(a[i] == - && b[i] == ){
++y;
}
}
// printf("x = %lld y = %lld\n",x,y);
f[] = JieCheng(x);
for(int i = ; i <= y; ++i){
f[i] = (x * f[i-] + (i-) * f[i-]) % MOD;
if(i > ) f[i] = (f[i] + (i-) * f[i-]) % MOD;
}
printf("%lld",f[y]);
return ;
}

Codeforces340 E. Iahub and Permutations的更多相关文章

  1. codeforces 341C Iahub and Permutations(组合数dp)

    C. Iahub and Permutations time limit per test 1 second memory limit per test 256 megabytes input sta ...

  2. codeforces 340E Iahub and Permutations(错排or容斥)

    转载请注明出处: http://www.cnblogs.com/fraud/          ——by fraud Iahub and Permutations Iahub is so happy ...

  3. cf-341C Iahub and Permutations

    C. Iahub and Permutations time limit per test 1 second memory limit per test 256 megabytes input sta ...

  4. Codeforces Round #198 (Div. 2) E. Iahub and Permutations —— 容斥原理

    题目链接:http://codeforces.com/contest/340/problem/E E. Iahub and Permutations time limit per test 1 sec ...

  5. CodeForces 340E Iahub and Permutations 错排dp

    Iahub and Permutations 题解: 令 cnt1 为可以没有限制位的填充数字个数. 令 cnt2 为有限制位的填充数字个数. 那么:对于cnt1来说, 他的值是cnt1! 然后我们对 ...

  6. CodeForces 340E Iahub and Permutations

    容斥原理,组合数. 找出有$cnt$个数字还有没放,那么总方案数就是$cnt!$. 总方案数里面包含了正确的和非正确的,我们需要将非正确的删去. 先删去$1$个数字$a[i]=i$的情况,发现会多删, ...

  7. CF341C. Iahub and Permutations [DP 排列]

    http://codeforces.com/contest/341/problem/C 题意: 有一个长度为n的排列a,其中有一些位置被替换成了-1.你需要尝试恢复这个排列,将-1替换回数字.求有多少 ...

  8. Iahub and Permutations(codeforces 314c)

    题意:给出一组排列,某些位置不知道(-1),要求求出有多少种还原方式,使得所有a[i]!=i /* 这是一道关于排列的动态规划,这种体大都可以当作棋盘来做,如果把i这个数放到第j个位置,那么就将棋盘的 ...

  9. Codeforces Round #198 (Div. 2)

    A.The Wall 题意:两个人粉刷墙壁,甲从粉刷标号为x,2x,3x...的小块乙粉刷标号为y,2y,3y...的小块问在某个区间内被重复粉刷的小块的个数. 分析:求出x和y的最小公倍数,然后做一 ...

随机推荐

  1. 一次掌握 React 与 React Native 两个框架

    此系列文章将整合我的 React 视频教程与 React Native 书籍中的精华部分,给大家介绍 React 与 React Native 结合学习的方法. 1. 软件开发语言与框架的学习本质 我 ...

  2. Logstash filter 的使用

    原文地址:http://techlog.cn/article/list/10182917 概述 logstash 之所以强大和流行,与其丰富的过滤器插件是分不开的 过滤器提供的并不单单是过滤的功能,还 ...

  3. java的instanceof关键字

    java 中的instanceof 运算符是用来判断对象是否是 特定类或这个特定类的子类 的一个实例. 用法: result = object instanceof class 参数: Result: ...

  4. Python入门-三级菜单

    作业题目: 三级菜单 作业需求: menu = { '北京':{ '海淀':{ '五道口':{ 'soho':{}, '网易':{}, 'google':{} }, '中关村':{ '爱奇艺':{}, ...

  5. rest-framework的权限组件

    权限组件 写在开头: 首先要在models表中添加一个用户类型的字段: class User(models.Model): name=models.CharField(max_length=32) p ...

  6. MYSQL mydumper & myloader

    第三方逻辑备份工具myduper和myloader | xiaoyu的数据库小窝-技术交流http://www.dbaxiaoyu.com/archives/1643 myloader原理0 - ze ...

  7. ntpd、ntpdate、hwclock的区别

    hwclock --systohc 使用ntpdate更新系统时间 - 潜龙勿用 - CSDN博客https://blog.csdn.net/suer0101/article/details/7868 ...

  8. node错误中间件处理 express类 带有路由操作

    let express = require('express'); let app = new express(); let bodyParser = require('body-parser'); ...

  9. Oracle 表分区(Partition)

    表分区功能能够改善应用程序性能,提高数据库可管理性和可用性,是数据库管理非常关键的技术.数据库通过使用分区提高查询性能,简化日常管理维护工作. 1 分区优点 1) 减少维护工作量,独立管理每个表分区比 ...

  10. Jenkins整合SonarQube代码检测工具

    借鉴博客:https://blog.csdn.net/kefengwang/article/details/54377055 上面这博客写得挺详细的,挺不错.它这个博客没有提供下载的教程,这个博客提供 ...