Flowey 是一朵能够通过友谊颗粒传播LOVE 的小花.它的友谊颗粒分为两种,
圆粒的和皱粒的,它们依次排列组成了一个长度为2m 的序列.对于一个友谊颗
粒的序列,如果存在 1<=i<j<=2m ,满足以下条件:
1)i 为偶数,j 为奇数
2)第i 颗友谊颗粒和第j 颗友谊颗粒同为圆粒或同为皱粒
3)第i 颗友谊颗粒和第j 颗友谊颗粒都还没有被使用过
那么,就可以使用这两颗友谊颗粒,然后提升一次LV.
定义一个友谊颗粒的序列为高效的,当且仅当尽可能多的提升LV 后,序列
上剩余的友谊颗粒数量不超过2n。
现在,Flowey 想知道,长度为2m 的友谊颗粒序列,有多少个不同的序列是
高效的?
定义两个友谊颗粒序列是不同的,当且仅当存在 1<=i<=2m ,第i颗友谊颗粒在
一个序列中为圆粒,而在另一个中为皱粒.
由于答案可能很大,你只需要求出答案对p 取模的结果.
这题的题解讲得不明不白的
这题的做法是先算出带重复的答案,再想办法去掉重复的,
把原来的序列就是01序列嘛,把它拆开成位置是偶数的序列和奇数的序列,
把它拆成上下两个序列,上边的是奇数的(序列a),下边的是偶数的(序列b)(这样好看),
这样,题目就变成了,对于每个位置i, ai 上的数字去匹配 b1 ~ bi−1 ,相同即匹配成功,(注意:是到i-1,不是到i)
为了好算,我们试着先保证a全部都要匹配上,那么就在 b1 的前面添加n个虚点,如果 ai 失配了,它就会连到虚点上,这些虚点有多少个0/1我们就先枚举,
这样,a就要保证全部匹配,
所以,b中(包括虚点)一定有n个是没有匹配的,
(看不懂没关系,继续往下看)
设DP: fi,j 表示做到点i,前面有j个0,(n-j)个1,
初始为 f0,0...n=1 ,(枚举0/1分别有多少个)
转移就直分4 种情况,分别枚举 ai,bi 是什么,
显然。这样会算重,因为:
比如:n=3,
对于一种转移方案,它用到了虚点中的2个1,
那么对于虚点为0,1,1的情况,它被计算了,
那么对于虚点为1,1,1的情况,它也被计算了,
原因是它只用了2个1,所以剩下那个是什么都没有影响,所以就重复了,
所以,只有当虚点中的0或1被全部用完了,这个状态才能被计算,(这样就不会重了嘛)
当然,如果有虚点有0且非虚点也有0,你强制去匹配虚点的而不是非虚点的,这样强制把虚点用完的不算,
也就是,在转移的过程中,如果有一个状态的j=0(0没了)或j=m(1没了),那么就表示它的虚点以用完了,以后也肯定是用完的(你不能然它吐出来吧),
所以多维护一个状态 fsi,j ,表示转移过来的所有状态中,有多少个是经过了k=0或j=m的,
转移方程与f一样,就是又这么一条:
if(0==j||j==m)fs[i][j]=f[i][j];
最后答案就是 fsn,i 之和
复杂度: O(nm)
#include
#define fo(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
typedef long long LL;
const int N=3500;
int read(int &n)
{
char ch=' ';int q=0,w=1;
for(;(ch!='-')&&((ch<'0')||(ch>'9'));ch=getchar());
if(ch=='-')w=-1,ch=getchar();
for(;ch>='0' && ch<='9';ch=getchar())q=q*10+ch-48;n=q*w;return n;
}
int m,n,mo,ans;
int f[N][N],fs[N][N];
int main()
{
freopen("friend.in","r",stdin);
freopen("friend.out","w",stdout);
int q,w;
read(m),read(n),read(mo);
fo(i,0,m)f[0][i]=1;
fo(i,1,n)
{
fo(j,0,m)
{
if(j1][j]+f[i-1][j+1]);
if(f[i][j]>=mo)f[i][j]-=mo;
fs[i][j]=(fs[i-1][j]+fs[i-1][j+1]);
if(fs[i][j]>=mo)fs[i][j]-=mo;
}
if(j)
{
f[i][j]+=f[i-1][j-1];
if(f[i][j]>=mo)f[i][j]-=mo;
fs[i][j]+=fs[i-1][j-1];
if(fs[i][j]>=mo)fs[i][j]-=mo;
f[i][j]+=f[i-1][j];
if(f[i][j]>=mo)f[i][j]-=mo;
fs[i][j]+=fs[i-1][j];
if(fs[i][j]>=mo)fs[i][j]-=mo;
}
if(!j||j==m)fs[i][j]=f[i][j];
}
}
ans=0;
fo(j,0,m)
{
ans+=fs[n][j];
if(ans>=mo)ans-=mo;
}
printf("%d\n",ans);
return 0;
}