There is a military class of 2∗n soldiers, and the commander wants all of them to get partnered into n pairs. He divides the soldiers into two lines of length n, and numbers the soldiers in both lines from 1 to n.
The ith numbered soldiers in the first line can be partnered with the jth numbered soldiers in the second line if |i−j|≤e. However, there are k pairs of soldiers that cannot be paired together. You need to print the number of ways you can match the soldiers into n pairs such that the constraints above are met. One way is different than the other if at least one soldiers has a different partner.
Input
The first line contains 3 integers n,e,k(1≤n≤2000,0≤e≤4,0≤k≤2000), the number of soldiers in each line, the value that determines the range, and the number of invalid pairs, respectively.
Each of the next k lines contains two integers ui,vi(1≤ui,vi≤n), the number of the soldiers from the first line and the number of the soldiers from the second line that cannot be matched together respectively. No pair of soldiers will appear twice in the input.
Output
Output the number of ways modulo 109+7, on a single line.
题解:
e<5,考虑状压DP,设dp[i][S]表示当前处理到第2行的第i个士兵,第一行中与之距离<=e的士兵的匹配情况,0表示还没有匹配到,1表示已经匹配到士兵了,考虑转移,枚举S中1的位置,那么对应i-1位置上的状态也可以推出来。再通过枚举高位为0/1转移即可
例如第i个士兵对应的状态为11010,从后往前枚举到了第2个士兵,那么先将当前位置0,我们就得到了11000,由于i-1位置上包含的是区间[i-1-e,i-1+e],i位置上包含的是区间[i-e,i+e],所以我们将得到的状态右移一位就得到了i-1位置上的后2*e位是1100,然后枚举高位位0/1,所以i位置上状态11010可以由i-1位置上状态11100或者01100,然后转移即可
AC代码:
#pragma GCC optimize(2)
#include<bits/stdc++.h>
#include<ext/rope>
using namespace std;
using namespace __gnu_cxx;
#define LL long long
const int MAXN = 2000+50;
const int MAXM = 2e5+50;
const int MOD = 1e9+7;
const int INF = 0x3f3f3f3f;
int n,e,p,mp[MAXN][MAXN]; LL dp[MAXN][(1<<10)+50];
inline void add(LL &x,LL y){ x=(x+y)%MOD; }
signed main(){
#ifndef ONLINE_JUDGE
freopen("C:\\Users\\Administrator\\Desktop\\in.txt","r",stdin);
#endif // ONLINE_JUDGE
scanf("%d%d%d",&n,&e,&p);
for(int i=1,x,y;i<=p;i++) scanf("%d%d",&x,&y),mp[x][y]=1;
for(int i=0;i<=e;i++) if(!mp[i][1]) dp[1][1<<i]=1;
for(int i=2;i<=n;i++){
for(int j=0;j<(1<<2*e+1);j++){
for(int k=0;k<2*e+1;k++){
if(i+e-k>n || i+e-k<=0) continue;
if(mp[i+e-k][i]) continue;
if(j&(1<<k)){
add(dp[i][j],dp[i-1][(j^(1<<k))>>1]);
add(dp[i][j],dp[i-1][((j^(1<<k))>>1)|(1<<2*e)]);
}
}
}
}
int sta=(1<<2*e+1)-1;LL res=0;
for(int i=0;i<e;i++) sta-=(1<<i);
cout<<dp[n][sta]<<'\n';
return 0;
}