G - Ban Permutation Editorial by TOMWT

No inclusion-exclusion

Got the idea from clein_qwqOrz

Consider the process of filling numbers as matching two rows of numbers. The final status is all \(2N\) numbers are matched.

Let’s call a number that is not matched yet delayed.

Let’s link an edge when processing the larger number it connects.

We need to store the number of delayed numbers in the range \([1,i]\) (that number is same for two rows). Also store whether a number in the range \([i-X+2,i]\) is matched.

When adding an edge with larger end at \(i+1\), so the number of ways to do that is the number of delayed numbers in the range \([1,i-X+1]\) in the other row.

Time complexity \(\mathcal O(N^24^{X-1})\)

#include<stdio.h>
#include<string.h>
#define mod 998244353
int n,m,mm,f[109][109][1<<8];
inline int dfs(int i,int j,int s)//0 for delayed and 1 for linked in s
{
	if(j>>31)return 0;//invalid status
	if(i==n)return!j;//work completed
	if(~f[i][j][s])return f[i][j][s];
	f[i][j][s]=0;
	f[i][j][s]=(f[i][j][s]+dfs(i+1,j+1,s<<2&mm))%mod;//delay both i+1
	f[i][j][s]=(f[i][j][s]+(long long)
		(j-__builtin_popcount(~s&mm&2+8+32+128))*
		dfs(i+1,j,(s<<2&mm)|1))%mod;
		//link i+1 in the first row with one of delayed numbers in the range [1,i-X+1] in the second row
		//delay i+1 in the second row
	f[i][j][s]=(f[i][j][s]+(long long)
		(j-__builtin_popcount(~s&mm&1+4+16+64))*
		dfs(i+1,j,(s<<2&mm)|2))%mod;//link i+1 in the second row
	f[i][j][s]=(f[i][j][s]+(long long)
		(j-__builtin_popcount(~s&mm&2+8+32+128))*
		(j-__builtin_popcount(~s&mm&1+4+16+64))*
		dfs(i+1,j-1,(s<<2&mm)|3))%mod;//link both i+1
	return f[i][j][s];
}
main()
{
	memset(f,-1,sizeof(f));
	scanf("%d%d",&n,&m);mm=(1<<m-1+m-1)-1;
	if(m>=n){putchar('0');return 0;}
	printf("%d",dfs(m-1,m-1,0));//delay first 2(X-1) numbers
}

posted:
last update: