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. 【开源】小程序、小游戏和Web运动引擎 to2to 发布

    简单轻量跨平台的 Javascript 运动引擎 Github → https://github.com/dntzhang/cax/tree/master/packages/to Simple DEM ...

  2. C#泛型创建实例

    class Test<T> where T : new() { public static T Instance() { return new T(); } } 就上面这方法, 居然比ne ...

  3. urllib库

    python内置的最基本的HTTP请求库,有以下四个模块: urllib.request 请求模块 urllib.error 异常处理模块 urllib.parse url解析模块 urllib.ro ...

  4. rbac权限+中间件

    1.权限组件rbac 1.什么是权限 1 项目与应用 2 什么是权限? 一个包含正则表达式url就是一个权限 who what how ---------->True or Flase 2.版本 ...

  5. CentOS7 修改MAC地址

    CentOS7 修改MAC地址 - mixboot - CSDN博客https://blog.csdn.net/u010953692/article/details/79650522

  6. PHP中友好的处理方式

    在使用PHP进行开发的时候,由于PHP是弱类型语言的特性,所以,偶尔会遇到一些意想不到的错误.规范我们的编程就变得尤为重要了.下面总结一下,我日常开发中的一些经验,可能有些地方不妥,还请多多斧正,指教 ...

  7. [转帖]HTTP 头部解释

    HTTP 头部解释 https://www.cnblogs.com/poissonnotes/p/4844014.html 之前看的太粗了 同事闻起来 referer 才知道自己所知甚少.. ==== ...

  8. Day 6-3 粘包现象

    服务端: import socket import subprocess phone = socket.socket(family=socket.AF_INET, type=socket.SOCK_S ...

  9. MySQL Connector/ODBC 2.50 (MyODBC 2.50)连接方式

    一.MySQL Connector/ODBC 2.50 (MyODBC 2.50)连接方式 1.本地数据库连接Driver={MySQL};Server=localhost;Option=16834; ...

  10. Ionic1.x项目中的Installing npm packages问题

    与npm远程源有关,可以通过cnpm来解决: 一.ionic start myApp blank --skip-npm(跳过Installing npm packages会产生的问题): 二.然后进入 ...