Codeforces 285E - Positions in Permutations(二项式反演+dp)
upd on 2021.10.20:修了个 typo(
这是一道 *2600 的 D2E,然鹅为啥我没想到呢?wtcl/dk
首先第一步我就没想到/kk,看到“恰好”二字我们可以想到一个东西叫做二项式反演(qwq 这个套路在刷多项式题时经常见到,可咋换个场景就想不到了呢?显然是我多项式白学了/doge)。我们设 \(f_k\) 表示恰好 \(k\) 个完美数的排列个数,\(g_k\) 表示钦定 \(k\) 个位置满足 \(|p_i-i|=1\),剩下随便乱填的方案数,那么显然对于某个有 \(x\) 个完美位置的排列,它被计入 \(g_y(y<x)\) 的次数为 \(\dbinom{x}{y}\)。
也就是说 \(g_k=\sum\limits_{i=k}^nf_i\dbinom{i}{k}\)。反演一下可得 \(f_k=\sum\limits_{i=k}^n(-1)^{i-k}\dbinom{i}{k}g_i\)。
故我们只需求出 \(g_i\) 就行了。
怎么求 \(g_i\) 呢?这时候就要用到 DP 了,我们设 \(dp_{i,j,x,y}\) 表示填好了前 \(i\) 个位置,钦定了 \(j\) 个位置满足 \(|p_i-i|=1\),\(x\) 表示 \(i\) 是否被选择,\(y\) 表示 \(i+1\) 是否被选择(这一步我又没想到,看来我 DP 也白学了/ww)。转移就分 \(i\) 不是被钦定为“完美位置”,\(p_i=i+1,p_i=i-1\) 三种情况转移即可,具体来说:
- \(dp_{i,j,0,0}=dp_{i-1,j,0,0}+dp_{i-1,j,1,0}+dp_{i-1,j-1,0,0}\)(放 \(i-1\) 或者不被钦定为完美位置)
- \(dp_{i,j,0,1}=dp_{i-1,j-1,0,0}+dp_{i-1,j-1,1,0}\)(\(y=1\),只能放 \(i+1\))
- \(dp_{i,j,1,0}=dp_{i-1,j,0,1}+dp_{i-1,j,1,1}+dp_{i-1,j-1,0,1}\)(放 \(i-1\) 或者不被钦定为完美位置)
- \(dp_{i,j,1,1}=dp_{i-1,j-1,0,1}+dp_{i-1,j-1,1,1}\)(\(y=1\),只能放 \(i+1\))
初始 \(dp_{1,0,0,0}=dp_{1,1,0,1}=1\)。
最后 \(g_k=(dp_{n,k,0,0}+dp_{n,k,1,0})·(n-k)!\)(\(n+1\) 不能被选择),时间复杂度 \(n^2\)。
#include <bits/stdc++.h>
using namespace std;
#define fi first
#define se second
#define fill0(a) memset(a,0,sizeof(a))
#define fill1(a) memset(a,-1,sizeof(a))
#define fillbig(a) memset(a,63,sizeof(a))
#define pb push_back
#define ppb pop_back
#define mp make_pair
template<typename T1,typename T2> void chkmin(T1 &x,T2 y){if(x>y) x=y;}
template<typename T1,typename T2> void chkmax(T1 &x,T2 y){if(x<y) x=y;}
typedef pair<int,int> pii;
typedef long long ll;
typedef unsigned int u32;
typedef unsigned long long u64;
namespace fastio{
#define FILE_SIZE 1<<23
char rbuf[FILE_SIZE],*p1=rbuf,*p2=rbuf,wbuf[FILE_SIZE],*p3=wbuf;
inline char getc(){return p1==p2&&(p2=(p1=rbuf)+fread(rbuf,1,FILE_SIZE,stdin),p1==p2)?-1:*p1++;}
inline void putc(char x){(*p3++=x);}
template<typename T> void read(T &x){
x=0;char c=getchar();T neg=0;
while(!isdigit(c)) neg|=!(c^'-'),c=getchar();
while(isdigit(c)) x=(x<<3)+(x<<1)+(c^48),c=getchar();
if(neg) x=(~x)+1;
}
template<typename T> void recursive_print(T x){if(!x) return;recursive_print(x/10);putc(x%10^48);}
template<typename T> void print(T x){if(!x) putc('0');if(x<0) putc('-'),x=~x+1;recursive_print(x);}
void print_final(){fwrite(wbuf,1,p3-wbuf,stdout);}
}
const int MAXN=1000;
const int MOD=1e9+7;
int n,m,dp[MAXN+5][MAXN+5][2][2];
int fac[MAXN+5],ifac[MAXN+5];
void add(int &x,int y){x+=y;if(x>=MOD) x-=MOD;}
int binom(int x,int y){return 1ll*fac[x]*ifac[y]%MOD*ifac[x-y]%MOD;}
int main(){
scanf("%d%d",&n,&m);dp[1][1][0][1]=dp[1][0][0][0]=1;
fac[0]=1;ifac[0]=ifac[1]=1;
for(int i=2;i<=n;i++) ifac[i]=1ll*ifac[MOD%i]*(MOD-MOD/i)%MOD;
for(int i=1;i<=n;i++) fac[i]=1ll*fac[i-1]*i%MOD,ifac[i]=1ll*ifac[i-1]*ifac[i]%MOD;
for(int i=2;i<=n;i++) for(int j=0;j<=i;j++){
if(j){
add(dp[i][j][0][0],dp[i-1][j-1][0][0]);
add(dp[i][j][1][0],dp[i-1][j-1][0][1]);
add(dp[i][j][0][1],dp[i-1][j-1][0][0]);
add(dp[i][j][0][1],dp[i-1][j-1][1][0]);
add(dp[i][j][1][1],dp[i-1][j-1][0][1]);
add(dp[i][j][1][1],dp[i-1][j-1][1][1]);
}
add(dp[i][j][0][0],dp[i-1][j][0][0]);
add(dp[i][j][0][0],dp[i-1][j][1][0]);
add(dp[i][j][1][0],dp[i-1][j][0][1]);
add(dp[i][j][1][0],dp[i-1][j][1][1]);
} int ans=0;
for(int i=m;i<=n;i++){
int ways=1ll*(dp[n][i][0][0]+dp[n][i][1][0])*fac[n-i]%MOD;
if((i-m)&1) ans=(ans-1ll*ways*binom(i,m)%MOD+MOD)%MOD;
else ans=(ans+1ll*ways*binom(i,m))%MOD;
} printf("%d\n",ans);
return 0;
}
Codeforces 285E - Positions in Permutations(二项式反演+dp)的更多相关文章
- CodeForces - 285E: Positions in Permutations(DP+组合数+容斥)
Permutation p is an ordered set of integers p1, p2, ..., pn, consisting of n distinct positive in ...
- BZOJ3622 已经没有什么好害怕的了 二项式反演+DP
题目传送门 https://lydsy.com/JudgeOnline/problem.php?id=3622 题解 首先显然如果 \(n - k\) 为奇数那么就是无解.否则的话,"糖果& ...
- CodeForces 340E Iahub and Permutations 错排dp
Iahub and Permutations 题解: 令 cnt1 为可以没有限制位的填充数字个数. 令 cnt2 为有限制位的填充数字个数. 那么:对于cnt1来说, 他的值是cnt1! 然后我们对 ...
- Codeforces 285 E. Positions in Permutations
\(>Codeforces \space 285 E. Positions in Permutations<\) 题目大意 : 定义一个长度为 \(n\) 的排列中第 \(i\) 个元素是 ...
- Codeforces 923E - Perpetual Subtraction(微积分+生成函数+推式子+二项式反演+NTT)
Codeforces 题目传送门 & 洛谷题目传送门 神仙题 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 首先考虑最朴素的 \(dp\),设 \(dp_{z,i}\) 表示经 ...
- P4859 已经没有什么好害怕的了(dp+二项式反演)
P4859 已经没有什么好害怕的了 啥是二项式反演(转) 如果你看不太懂二项式反演(比如我) 那么只需要记住:对于某两个$g(i),f(i)$ ---------------------------- ...
- 洛谷4859 BZOJ3622 已经没什么好害怕的了(DP,二项式反演)
题目链接: 洛谷 BZOJ 题目大意:有两个长为 $n$ 的序列 $a,b$,问有多少种重排 $b$ 的方式,使得满足 $a_i>b_i$ 的 $i$ 的个数比满足 $a_i<b_i$ 的 ...
- BZOJ3622 已经没有什么好害怕的了 【dp + 二项式反演】
题目链接 BZOJ3622 题解 既已开题 那就已经没有什么好害怕的了 由题目中奇怪的条件我们可以特判掉\(n - k\)为奇数时答案为\(0\) 否则我们要求的就是糖果大于药片恰好有\(\frac{ ...
- 51nod 1518 稳定多米诺覆盖(容斥+二项式反演+状压dp)
[传送门[(http://www.51nod.com/Challenge/Problem.html#!#problemId=1518) 解题思路 直接算不好算,考虑容斥,但并不能把行和列一起加进去容斥 ...
随机推荐
- nssm.exe使用方法
nssm no-sucking service manager 1. 安装服务命令 nssm install <servicename> nssm install <servicen ...
- UVA-1498 Activation
UVA-1498 DP应该是肯定的,设 f [ i ] [ j ] 表示现在对中共有 i 人,Tomato在第 j 个,出现所求情况的概率,我们可以很(简单的)艰难的列出下列方程: f[i][1] = ...
- TVS管性能及选型总结
https://wenku.baidu.com/view/5b5bda5526fff705cc170af8.html
- 利用DMA实现采样数据的直接搬运存储
尝试了下STM32的ADC采样,并利用DMA实现采样数据的直接搬运存储,这样就不用CPU去参与操作了. 找了不少例子参考,ADC和DMA的设置了解了个大概,并直接利用开发板来做一些实验来验证相关的操作 ...
- 用python检查矩阵的计算
鉴于最近复习线性代数计算量较大,且1800答案常常忽略一些逆阵.行列式的计算答案,故用Python写出矩阵的简单计算程序,便于检查出错的步骤. 1.行列式 可自行更改阶数 from numpy imp ...
- 全志Tina_dolphin播放音视频裸流(h264,pcm)验证
最近在验证tina对裸流音视频的支持,主要指h264视频裸流及pcm音频裸流. 在原始sdk中有针对很多video和audio类型的parser,但就是没有找到pcm和h264的parser,所以需要 ...
- freeswitch的docker构建过程
概述 Docker是一个开源的应用容器引擎,可以让开发者打包应用以及依赖包到一个轻量级.可移植的容器中,并在任何安装有Docker的机器上运行. Docker 使你能够将应用程序与基础架构分开,从而可 ...
- Linux环境下安装中山大学东校区iNode客户端
在中山大学登录校园网有两种方式,一种是连接WiFi,另一种是连接网线.这两种上网方式都需要用到NetID,但是连接网线的话还需要使用到iNode客户端(指东校区). Windows下iNode客户端的 ...
- Centos7上安装docker (新手版本)
1首先要有一个安装好的Centos7 2打开终端,输入一下命令(自动安装最新版本) curl -fsSL https://get.docker.com | bash -s docker --mirro ...
- 折腾systemd-nspawn运行centos7
Archlinux创建Debian/Ubuntu的systemd-nspawn容器是很简单的,因为有debootstrap软件.某天我突然想装个centos7玩玩,搜了半天没发现有什么类似于deboo ...