先贴上个代码。
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=105;
const int maxp=15;
const int maxs=200000;
const int mod=10007;
int N,P,k;
int dp[maxn][maxs];
bool exist[maxn];
int Encode(int *a,int n){
int ret=0;
for(int i=0;i<n;++i)
ret=ret*3+a[i];
return ret;
}
void Decode(int *a,int n,int s){
for(int i=n-1;i>=0;--i){
a[i]=s%3;
s/=3;
}
}
void Move(int *a,int n){
for(int i=n;i>0;--i)
a[i]=a[i-1];
a[0]=0;
}
void add(int &u,int v){u=(u+v)%mod;}
int solve(){
int n=P+2;
int idx[3],cur[maxp],nxt[maxp];
idx[0]=1;idx[1]=P;idx[2]=P+2;
for(int i=0;i<n;++i) cur[i]=2;
int e=Encode(cur,n);
dp[0][e]=1;
for(int i=0;i<N;++i){
for(int s=0;s<=e;++s){
if(dp[i][s]==0)continue;
Decode(cur,n,s);
memcpy(nxt,cur,sizeof(cur));
Move(nxt,n);
if(exist[i+1]){
nxt[0]=2;
if(nxt[n]==2) add(dp[i+1][Encode(nxt,n)],dp[i][s]);
continue;
}
if (nxt[n]==2) add(dp[i+1][Encode(nxt,n)],dp[i][s]);
// 向前连一条边
nxt[0]=1;
for (int j=0;j<3;j++) {
int&v=nxt[idx[j]];
if (v<2){
v++;
if(nxt[n]==2) add(dp[i+1][Encode(nxt,n)],dp[i][s]);
v--;
}
}
// 向前连两条边
nxt[0]=2;
for (int j=0; j<3;j++) {
for (int k=j+1;k<3;k++) {
int&u=nxt[idx[j]];
int&v=nxt[idx[k]];
if (u<2&&v<2) {
u++,v++;
if(nxt[n]==2) add(dp[i+1][Encode(nxt,n)],dp[i][s]);
u--,v--;
}
}
}
}
}
return dp[N][e];
}
int main(){
int T,t;
scanf("%d",&T);
for(int ca=1;ca<=T;++ca){
memset(exist,false,sizeof(exist));
memset(dp,0,sizeof(dp));
scanf("%d %d",&N,&P);
scanf("%d",&k);
for(int i=0;i<k;++i){
scanf("%d",&t);
exist[t]=true;
}
printf("Case #%d: %d\n",ca,solve());
}
return 0;
}