题目大意
有一个01序列。
有m个约束第i个约束为前xi和为yi与后yi和为xi两个条件至少满足一个。
求有多少种合法序列
随便搞搞
如果xi和yi不等,那么我们直接能判断出那个条件是必须满足的。
对于xi和yi相等的,找到最大的记为p。
接着我们容斥,左边至少p个连续1+右边至少p个连续1-两边都至少p个连续1。
现在说说已知一堆约束怎么求序列个数。
枚举序列中总共1的个数,然后后缀约束可以转化为前缀约束。
于是我们现在全部都是前缀约束啦!
先注意判其中一种无解(其实就是保证每个位置只有一个约束
),即不能存在两个约束发生矛盾,如两个约束均在位置i但限制的数量不等。
这样左后仍然可能无解啊?但没关系,待会会说。
于是序列可以被分成许多段,每一段的长度与1的个数我们都知道,组合数即可。
如果还无解在乘组合数时会乘上0,因此没有关系。
#include<cstdio>
#include<algorithm>
#define fo(i,a,b) for(i=a;i<=b;i++)
#define fd(i,a,b) for(i=a;i>=b;i--)
using namespace std;
typedef long long ll;
const int maxn=5000+10,mo=998244353;
struct dong{
int x,y;
bool p;
} a[maxn],b[maxn];
int f[maxn],g[maxn],num[maxn];
int i,j,k,l,t,n,m,p,ca,tot,top,ans;
bool czy;
int quicksortmi(int x,int y){
if (!y) return 1;
int t=quicksortmi(x,y/2);
t=(ll)t*t%mo;
if (y%2) t=(ll)t*x%mo;
return t;
}
int c(int n,int m){
if (n<0||m<0) return 0;
if (n<m) return 0;
return (ll)f[n]*g[m]%mo*g[n-m]%mo;
}
void work(){
int i;
fo(i,0,n) num[i]=-1;
fo(i,1,tot)
if (a[i].y<0){
czy=0;
return;
}
fo(i,1,tot)
if (num[a[i].x]==-1||num[a[i].x]==a[i].y) num[a[i].x]=a[i].y;
else{
czy=0;
return;
}
}
int main(){
//freopen("ex_A2.in","r",stdin);
scanf("%d",&ca);
while (ca--){
ans=0;
scanf("%d%d",&n,&m);
f[0]=1;
fo(i,1,n) f[i]=(ll)f[i-1]*i%mo;
g[n]=quicksortmi(f[n],mo-2);
fd(i,n-1,0) g[i]=(ll)g[i+1]*(i+1)%mo;
p=tot=top=0;
fo(i,1,m){
scanf("%d%d",&j,&k);
if (j==k) p=max(p,j);
else if (j>k){
a[++tot].x=j;
a[tot].y=k;
a[tot].p=0;
}
else{
a[++tot].x=n-k+1;
a[tot].y=j;
a[tot].p=1;
}
}
a[++tot].x=0;
a[tot].y=0;
a[tot].p=0;
if (p){
a[++tot].x=p;
a[tot].y=p;
a[tot].p=0;
}
fo(i,1,tot) b[i]=a[i];
fo(i,1,n){
a[++tot].x=n;
a[tot].y=i;
a[tot].p=0;
fo(j,1,tot)
if (a[j].p){
a[j].x--;
a[j].y=i-a[j].y;
}
czy=1;
work();
if (!czy){
tot--;
fo(j,1,tot) a[j]=b[j];
continue;
}
t=1;
k=0;l=0;
fo(j,1,n){
if (num[j]!=-1){
t=(ll)t*c(j-k,num[j]-l)%mo;
k=j;
l=num[j];
}
}
ans=(ans+t)%mo;
tot--;
fo(j,1,tot) a[j]=b[j];
}
tot--;
if (p){
a[++tot].x=n-p+1;
a[tot].y=p;
a[tot].p=1;
}
fo(i,1,tot) b[i]=a[i];
fo(i,1,n){
a[++tot].x=n;
a[tot].y=i;
a[tot].p=0;
fo(j,1,tot)
if (a[j].p){
a[j].x--;
a[j].y=i-a[j].y;
}
czy=1;
work();
if (!czy){
tot--;
fo(j,1,tot) a[j]=b[j];
continue;
}
t=1;
k=0;l=0;
fo(j,1,n){
if (num[j]!=-1){
t=(ll)t*c(j-k,num[j]-l)%mo;
k=j;
l=num[j];
}
}
ans=(ans+t)%mo;
tot--;
fo(j,1,tot) a[j]=b[j];
}
if (p){
a[++tot].x=p;
a[tot].y=p;
a[tot].p=0;
}
fo(i,1,tot) b[i]=a[i];
fo(i,1,n){
a[++tot].x=n;
a[tot].y=i;
a[tot].p=0;
fo(j,1,tot)
if (a[j].p){
a[j].x--;
a[j].y=i-a[j].y;
}
czy=1;
work();
if (!czy){
tot--;
fo(j,1,tot) a[j]=b[j];
continue;
}
t=1;
k=0;l=0;
fo(j,1,n){
if (num[j]!=-1){
t=(ll)t*c(j-k,num[j]-l)%mo;
k=j;
l=num[j];
}
}
ans=((ans-t)%mo+mo)%mo;
tot--;
fo(j,1,tot) a[j]=b[j];
}
printf("%d\n",ans);
}
}