传送门:http://codeforces.com/problemset/problem/1207/D
反向求good array,那就在总方案数 n! 中把bad array全部减掉
我们先把数组按照a排序,那么因为第一维是不降的方案就可以计算出来了,就是对于相同的一段a,他们内部可以随便交换位置,那么这段长度为len的相同的a就可以贡献 len! ,把所有len!乘起来就是 第一维不降的方案tmp1
同理按照b排序,求出第二维不降的总方案数tmp2。
现在要算出那些重复的方案tmp3,那就是第一维不降第二维也不降的方案。
那么们就在按a排序的基础上,在一段相同a的内部按b排序,然后我们看整个序列是否满足b不降,如果满足,则去每一段相同的a中 找 b 相同连续段,然后通过上面一样的方式乘出tmp3。如果不满足,那么说明没有重复方案,tmp3=0
最后答案就是 n!-tmp1-tmp2+tmp3
#include<bits/stdc++.h>
#define maxl 400010
using namespace std;
const int mod=998244353;
int n,m,bcnt,ccnt,tcnt;
long long ans;
struct node
{
int a,b;
}a[maxl],b[maxl],c[maxl];
int bpos[maxl],blen[maxl];
int cpos[maxl],clen[maxl];
int tlen[maxl];
long long jc[maxl];
char s[maxl];
inline void prework()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d%d",&a[i].a,&a[i].b);
b[i]=a[i];c[i]=a[i];
}
}
inline bool cmpa(const node &x,const node &y)
{
return x.a<y.a;
}
inline bool cmpb(const node &x,const node &y)
{
return x.b<y.b;
}
inline void mainwork()
{
sort(b+1,b+1+n,cmpa);
sort(c+1,c+1+n,cmpb);
long long tmp1=1,tmp2=1,tmp3=1;
bcnt=0;
for(int i=1;i<=n;i++)
if(b[i].a==b[i-1].a)
bpos[i]=bcnt,blen[bcnt]++;
else
{
tmp1=tmp1*jc[blen[bcnt]]%mod;
bcnt++;
bpos[i]=bcnt;blen[bcnt]=1;
}
tmp1=tmp1*jc[blen[bcnt]]%mod;
ccnt=0;
for(int i=1;i<=n;i++)
if(c[i].b==c[i-1].b)
cpos[i]=ccnt,clen[ccnt]++;
else
{
tmp2=tmp2*jc[clen[ccnt]]%mod;
ccnt++;
cpos[i]=ccnt;clen[ccnt]=1;
}
tmp2=tmp2*jc[clen[ccnt]]%mod;
for(int i=1;i<=n;i++)
{
sort(b+i,b+i+blen[bpos[i]],cmpb);
i=i+blen[bpos[i]]-1;
}
bool flag=true;
for(int i=2;i<=n;i++)
if(b[i].b<b[i-1].b)
flag=false;
if(flag)
{
for(int i=1;i<=n;i++)
{
tcnt=0;
for(int j=i;j<=i+blen[bpos[i]]-1;j++)
if(b[j].a==b[j-1].a && b[j].b==b[j-1].b)
tlen[tcnt]++;
else
{
tmp3=tmp3*jc[tlen[tcnt]]%mod;
tcnt++;
tlen[tcnt]=1;
}
tmp3=tmp3*jc[tlen[tcnt]]%mod;
i=i+blen[bpos[i]]-1;
}
}
else
tmp3=0;
ans=((jc[n]-tmp1)%mod+mod)%mod;
ans=((ans-tmp2)%mod+mod)%mod;
ans=(ans+tmp3)%mod;
}
inline void print()
{
printf("%lld\n",ans);
}
int main()
{
int t=1;
//scanf("%d",&t);
jc[0]=1;
for(int i=1;i<maxl;i++)
jc[i]=jc[i-1]*i%mod;
for(int i=1;i<=t;i++)
{
prework();
mainwork();
print();
}
return 0;
}