题目大意
给你n个二元组
问你有几种排列是的按两个关键字中的任意一个都不是不降排列的
分析
不妨容斥
我们先加上总的方案数$n!$
之后我们按第一个关键字排序
因为值相同的情况下不影响答案
所以让总方案数减去$prod sum_{ai}!$即可
对于第二关键字的情况同上
我们再使序列同时按照第一关键字和第二关键字排序
然后总方案数加上$prod sum_{(ai,bi)}!$即可
代码
#include<iostream> #include<cstdio> #include<cstring> #include<string> #include<algorithm> #include<cctype> #include<cmath> #include<cstdlib> #include<queue> #include<ctime> #include<vector> #include<set> #include<map> #include<stack> using namespace std; #define int long long const int mod = 998244353; int p[300100],n,m,Ans; struct node { int x,y; }; node d[300100]; inline void init(){ int i,j,k; p[0]=1; for(i=1;i<=n;i++)p[i]=p[i-1]*i%mod; } inline bool cmp1(const node a,const node b){ if(a.x==b.x)return a.y<b.y; return a.x<b.x; } inline bool cmp2(const node a,const node b){ return a.y<b.y; } signed main(){ int i,j,k; scanf("%lld",&n); init(); for(i=1;i<=n;i++)scanf("%lld%lld",&d[i].x,&d[i].y); Ans=p[n]; sort(d+1,d+n+1,cmp1); int res=1; for(i=1;i<=n;i++){ j=i; while(j+1<=n&&d[j+1].x==d[j].x)j++; res=res*p[j-i+1]%mod; i=j; } Ans=(Ans-res+mod)%mod; sort(d+1,d+n+1,cmp2); res=1; for(i=1;i<=n;i++){ j=i; while(j+1<=n&&d[j+1].y==d[j].y)j++; res=res*p[j-i+1]%mod; i=j; } Ans=(Ans-res+mod)%mod; sort(d+1,d+n+1,cmp1); int ok=1; for(i=2;i<=n;i++) if(d[i].y<d[i-1].y){ ok=0; break; } res=1; if(ok){ for(i=1;i<=n;i++){ j=i; while(j+1<=n&&d[j+1].y==d[j].y&&d[j+1].x==d[j].x)j++; res=res*p[j-i+1]%mod; i=j; } Ans=(Ans+res)%mod; } cout<<Ans<<" "; return 0; }