【xsy2303】呀 dp

题目大意:你需要构造一个长度为n的排列A,使得里面包含有子序列B(子序列B为一个给定的1m的排列),且对于每个i,有A[A[i]]=i,问有多少种方案方案。

数据范围:n107,m500,答案对109+7取模

 

我们首先不考虑有m的存在,考虑如何构造一个符合条件的序列A

我们发现我们可以DP,设f[i]表示有多少种长度为i的序列满足A[A[i]]=i

对于第i个数,我们可以考虑把它填在原位,或者放在第j个位置,然后在A[i]处填上j

根据这个,不难推出f[i]=(i1)f[i2]+f[i1]

 

我们下面考虑,序列B的前k个数,位于A中前m个位置,剩余的mk个,位于后nm个位置。

我们发现,对于剩余的mk个数,对应的AB[i],都会被占用,用来填(填写了B[i]的位置)。

所以我们需要在前m个位置里,用恰好k个位置,按顺序填出序列Bk个数字。

不难发现,至多只有一种填法。

对于B[i],我们找到序列A中第i个可以填数的地方,直接填入B[i]即可。

最后O(m)扫一遍判断即可。

如果可行,那么剩下的nk个位置中,需要找出mk个位置放置B[k+1],B[k+2].....B[m],并且在A[B[k+1]]等地方填上它们的位置。

剩下的n2m+k个位置,就可以随便填>m的数了,方案数显然是f[n2m+k]

所以方案数为(nkmk)×f[n2m+k]

我们对于每个不超过m的k全部处理一遍就可以了。

时间复杂度:O(n+m2)

 

复制代码
 1 #include<bits/stdc++.h>
 2 #define MOD 1000000007
 3 #define L long long
 4 #define M 10000005
 5 using namespace std;
 6 
 7 L fac[M]={0},invfac[M]={0},f[M]={0};
 8 L pow_mod(L x,L k){L ans=1;for(;k;k>>=1,x=x*x%MOD) if(k&1) ans=ans*x%MOD; return ans;}
 9 L C(int n,int m){return fac[n]*invfac[m]%MOD*invfac[n-m]%MOD;}
10 
11 L mark[M]={0},b[M]={0},a[M]={0},ans=0,n,m;
12 void solve(int k){
13     if(n-m<m-k) return;
14     for(int i=1,j=1;i<=k;i++,j++){
15         while(!mark[j]) j++;
16         a[j]=b[i];
17     }
18     for(int i=1;i<=m;i++)
19     if(mark[i]&&a[a[i]]!=i) return;
20     ans=(ans+C(n-m,m-k)*f[n-m-m+k])%MOD;
21 }
22 int main(){
23     fac[0]=1; for(int i=1;i<M;i++) fac[i]=fac[i-1]*i%MOD;
24     invfac[M-1]=pow_mod(fac[M-1],MOD-2);
25     for(int i=M-2;~i;i--) invfac[i]=invfac[i+1]*(i+1)%MOD;
26     f[0]=f[1]=1; for(int i=2;i<M;i++) f[i]=(f[i-1]+f[i-2]*(i-1))%MOD;
27     
28     scanf("%d%d",&n,&m);
29     for(int i=1;i<=m;i++) scanf("%d",b+i);
30     for(int k=0;k<=m;k++){
31         mark[b[k]]=1;
32         solve(k);
33     }
34     cout<<ans<<endl;
35 }
复制代码
posted @   AlphaInf  阅读(169)  评论(0编辑  收藏  举报
编辑推荐:
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
阅读排行:
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 零经验选手,Compose 一天开发一款小游戏!
· 一起来玩mcp_server_sqlite,让AI帮你做增删改查!!
点击右上角即可分享
微信分享提示