Description
一个长度为2m的序列,每个位置可以是0或1
任意两个i < j,i为偶数,j为奇数的0/1相同的位置可以匹配,每个位置最多匹配一次
求有多少个序列满足匹配完剩余的位置<=2n
答案对p取模
n,m<=3000,p<=1e9+7
Solution
一道吼题,正解有些猎奇
首先考虑mn^2Dp,这个相信大家都会,设Fi,j,k表示前i个位置,剩余j个可匹配0,k个可匹配1的方案
如何优化?
我们考虑在最前面多放上n个可匹配的位置,这样合法状态一定没有剩余
并且发现可供匹配的位置数量恒为n
那么我们就可以设Fi,j表示前i个位置,有j个可匹配0的方案(此时有n-j个可匹配1)
但是这样会算重?!
我们发现如果我们添加的某种供给匹配点如果没有用完的话这个状态就会被算重
所以多加一维表示这个状态是否经历过j=0,即可匹配0用完的方案
这样就可以通过本题
Code
#include <cstdio>
#include <cstring>
#include <algorithm>
#define fo(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
typedef long long ll;
int read() {
char ch;
for(ch=getchar();ch<'0'||ch>'9';ch=getchar());
int x=ch-'0';
for(ch=getchar();ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0';
return x;
}
int n,m,p;
void inc(int &x,int y) {
if (y>=p) y=y-p;
x=x+y;
if (x>=p) x=x-p;
}
void init() {
n=read();m=read();p=read();
}
#define min(x,y) (x<y?x:y)
const int N=3*1e3+5;
int f[N][N][2],ans;
void solve() {
fo(i,1,n) f[0][i][0]=1;
f[0][0][1]=1;
fo(i,0,m-1)
fo(j,0,n)
fo(z,0,1)
if (f[i][j][z])
if (j>1&&j<n) {
inc(f[i+1][j-1][!(j-1)||z],f[i][j][z]);
inc(f[i+1][j+1][z],f[i][j][z]);
inc(f[i+1][j][z],f[i][j][z]*2);
} else if (!j) {
inc(f[i+1][j][z],f[i][j][z]);
inc(f[i+1][j+1][z],f[i][j][z]);
} else if (j==1) {
inc(f[i+1][j][1],f[i][j][z]);
inc(f[i+1][j-1][!(j-1)||z],f[i][j][z]);
if (n!=1) {
inc(f[i+1][j+1][z],f[i][j][z]);
inc(f[i+1][j][z],f[i][j][z]);
}
} else {
inc(f[i+1][j][z],f[i][j][z]);
inc(f[i+1][j-1][z],f[i][j][z]);
}
fo(i,0,n) inc(ans,f[m][i][1]);
printf("%d\n",ans);
}
int main() {
freopen("friend.in","r",stdin);
freopen("friend.out","w",stdout);
init();solve();
return 0;
}