[agc013d] Pilling Up

xiaoxiao2021-02-28  69

题目大意

有两种元素,一种0一种1,一开始,你可以随便拿01,总共拿n个。 然后你进行m次操作,每次操作先从手上拿一个元素,放在你的构造序列末尾,然后再获得0,1各一个,然后再放一次。 问最后有多少种不同的序列。 n,m<=3000

解题思路

一个很简单的想法是设f[i][j]表示做了第i轮,剩下j个0的时候,有多少种不同的序列。 然后根据题意转移。 但是如果直接把f[0][0~n]=1,那么就会出现一种序列被多个初始状态转移到。 考虑去重。我们让一种序列归进初始0最少的状态里,那么肯定在中途出现过0刚好用完的情况。 那么多开一维即可,表示这个状态在之前的转移的时候有没有出现过0用完。 复杂度O(nm)

代码

#include<cstdio> #include<algorithm> #include<cstring> #include<cmath> #include<set> #include<map> using namespace std; #define fo(i,j,k) for(i=j;i<=k;i++) #define fd(i,j,k) for(i=j;i>=k;i--) #define cmax(a,b) (a=(a>b)?a:b) #define cmin(a,b) (a=(a<b)?a:b) typedef long long ll; const int N=1e6+5,M=2e6+5,mo=1e9+7; ll f[3005][3005][2]; int n,m,i,j,k,ans; int main() { freopen("t7.in","r",stdin); //freopen("t7.out","w",stdout); scanf("%d %d",&n,&m); fo(i,0,n) f[0][i][i==0]=1; fo(i,0,m-1) fo(j,0,n) fo(k,0,1) { if (j) (f[i+1][j-1][k|(j==1)]+=f[i][j][k])%=mo; if (j) (f[i+1][j][k|(j==1)]+=f[i][j][k])%=mo; if (n-j) (f[i+1][j+1][k]+=f[i][j][k])%=mo; if (n-j) (f[i+1][j][k]+=f[i][j][k])%=mo; } fo(i,0,n) ans=(ans+f[m][i][1])%mo; printf("%d\n",ans%mo); }
转载请注明原文地址: https://www.6miu.com/read-2631962.html

最新回复(0)