考虑按 1 ∼ n 1\sim n 1∼n的顺序插入序列。将答案除以 n n n即可。
那么我们唯一要干的事情就是把哪些位置是 固定的 给找出来。
首先,如果一个数小于等于 i − 4 i-4 i−4,那么它的旁边都不能插数,可以看作是固定的。并且对于小于等于 i − 4 i-4 i−4的数,因为在后续填数的过程中不会影响其左右两边的数,因此在当前状态下一定是合法的。换言之,当填入 i i i过后,我们只需要检验 i − 3 i-3 i−3是否合法即可。故而,我们只需要关注 i − 3 , i − 2 , i − 1 i-3,i-2,i-1 i−3,i−2,i−1的相对位置关系,以及是否相邻。这显然可以用最暴力的状压解决,然后就做完了。这玩意用顺逆时针来记录会更简单一些,剩下的全部是手动分讨。
我承认,这个做法非常垃圾。这也导致了代码非常难打。
#include<bits/stdc++.h>
#define ll long long
#define fi first
#define se second
#define pb push_back
#define inf 0x3f3f3f3f
using namespace std;
const int N=1e6+5;
const int mod=1e9+7;
int n,K,D,p[3],ban[N][10],now[2][8],nxt[2][8],res,state[N];
vector<int>vec;
void add(int &x,int y){x=(x+y)%mod;}
int check(){
vec.clear();
for(int i=1;i<=n;i++){
if(!state[i]){
vec.pb(i);
}
}
for(int i=n;i>=1;i--){
if(state[i]){
vec.pb(i);
}
}
for(int i=0;i+1<vec.size();i++){
if(ban[vec[i]][vec[i+1]-vec[i]+3])return 0;
}
if(ban[vec.back()][vec[0]-vec.back()+3])return 0;
return 1;
}
int check(int x,int y){
return ban[x][y-x+3];
}
void solve1(int x,int s){
int sig=s>>1&1;
if((s&1)&&(!(s&4)||!check(x-1,x-3))&&!check(x-3,x)){
add(nxt[0][4|sig],now[0][s]);
}
if((s&2)&&(!(s&1)||!check(x-3,x-2))&&(!(s&4)||!check(x-1,x-3))){
add(nxt[1][3],now[0][s]);
}
if((s&4)&&(!(s&1)||!check(x-3,x-2))&&!check(x,x-3)){
add(nxt[0][2|sig],now[0][s]);
}
}
void solve2(int x,int s){
int sig=s>>1&1;
if((s&1)&&(!(s&4)||!check(x-2,x-3))&&!check(x-3,x)){
add(nxt[1][2|(sig<<2)],now[1][s]);
}
if((s&2)&&(!(s&1)||!check(x-3,x-1))&&(!(s&4)||!check(x-2,x-3))){
add(nxt[0][6],now[1][s]);
}
if((s&4)&&(!(s&1)||!check(x-3,x-1))&&!check(x,x-3)){
add(nxt[1][1|(sig<<2)],now[1][s]);
}
}
int solve(){
if(D==0){
if(n==1)return 1;
return 0;
}
if(D==1){
if(n==1)return 1;
else if(n==2){
if(ban[1][2-1+3]||ban[2][1-2+3])return 0;
return 1;
}
else{
return 0;
}
}
if(D==2){
//最多只有两种情况
if(n==1)return 1;
else if(n==2){
if(ban[2-1+3]||ban[1-2+3])return 0;
return 1;
}
for(int i=1;i<=n;i+=2)state[i]=0;
for(int i=2;i<=n;i+=2)state[i]=1;
res+=check();
state[1]=0;
for(int i=2;i<=n;i+=2)state[i]=0;
for(int i=3;i<=n;i+=2)state[i]=1;
res+=check();
return res;
}
if(n==1){
return 1;
}
if(n==2){
if(ban[2-1+3]||ban[1-2+3])return 0;
return 1;
}
now[0][7]=now[1][7]=1;
for(int i=4;i<=n;i++){
memset(nxt,0,sizeof nxt);
for(int j=0;j<2;j++){
for(int k=0;k<8;k++){
if(now[j][k]){
if(j==0){
solve1(i,k);
}
else{
solve2(i,k);
}
}
}
}
memcpy(now,nxt,sizeof nxt);
}
for(int i=0;i<2;i++){
for(int j=0;j<8;j++){
if(now[i][j]){
if(i==0){
if((!(j&1)||!check(n-2,n-1))&&(!(j&2)||!check(n-1,n))&&(!(j&4)||!check(n,n-2))){
add(res,now[i][j]);
}
}
else{
if((!(j&1)||!check(n-2,n))&&(!(j&2)||!check(n,n-1))&&(!(j&4)||!check(n-1,n-2))){
add(res,now[i][j]);
}
}
}
}
}
return res;
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0),cout.tie(0);
cin>>n>>K>>D;
for(int i=1;i<=K;i++){
int a,b;cin>>a>>b;
if(abs(a-b)<=3){
ban[a][b-a+3]=1;
}
}
cout<<solve();
}