【xsy2303】呀 dp
题目大意:你需要构造一个长度为n的排列A,使得里面包含有子序列B(子序列B为一个给定的1到m的排列),且对于每个i,有A[A[i]]=i,问有多少种方案方案。
数据范围:n≤107,m≤500,答案对109+7取模
我们首先不考虑有m的存在,考虑如何构造一个符合条件的序列A。
我们发现我们可以DP,设f[i]表示有多少种长度为i的序列满足A[A[i]]=i。
对于第i个数,我们可以考虑把它填在原位,或者放在第j个位置,然后在A[i]处填上j。
根据这个,不难推出f[i]=(i−1)f[i−2]+f[i−1]。
我们下面考虑,序列B的前k个数,位于A中前m个位置,剩余的m−k个,位于后n−m个位置。
我们发现,对于剩余的m−k个数,对应的AB[i],都会被占用,用来填(填写了B[i]的位置)。
所以我们需要在前m个位置里,用恰好k个位置,按顺序填出序列B前k个数字。
不难发现,至多只有一种填法。
对于B[i],我们找到序列A中第i个可以填数的地方,直接填入B[i]即可。
最后O(m)扫一遍判断即可。
如果可行,那么剩下的n−k个位置中,需要找出m−k个位置放置B[k+1],B[k+2].....B[m],并且在A[B[k+1]]等地方填上它们的位置。
剩下的n−2m+k个位置,就可以随便填>m的数了,方案数显然是f[n−2m+k]
所以方案数为(n−km−k)×f[n−2m+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 }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 零经验选手,Compose 一天开发一款小游戏!
· 一起来玩mcp_server_sqlite,让AI帮你做增删改查!!