标签:names force flag define col ret point mod code
题意:给你n个坐标,求组成序列的总数,其中x,y都不能升序。
思路:刚开始就想到了思路,但情况没有特判对。因为总共的序列有n!种,因为xy都不能升序,所以先给x,y分别排序,例如给x排升序,x里面的每一组重复的数的排列就是对于x来说不符合情况的种数,就应该减去每个重复的x个数的阶乘之积。y也是如此,但是你减去了可能重复的情况,那就是x,y都升序,且重复。所以还要加上这种情况算出来的种数。首先要特判一下有没有这种情况。代码上注释很清楚,上代码。
#include<cstring> #include<algorithm> #include<vector> #include<map> #include<queue> #include<cstdio> #include<cmath> #define ll long long #define lowbit(x) x&(-x) using namespace std; const int mod=998244353; int n,i,j,m; ll ans,p[300005],s; struct point { int x; int y; }a[300005]; bool cmp(point a,point b) { if(a.x==b.x) return a.y<b.y; return a.x<b.x; } bool cmp2(point a,point b) { return a.y<b.y; } int main() { scanf("%d",&n); p[0]=1; for(i=1;i<=n;i++) { scanf("%d %d",&a[i].x,&a[i].y); p[i]=p[i-1]*i%mod; } ans=p[n]; sort(a+1,a+1+n,cmp); int flag=0; for(i=2;i<=n;i++) if(!(a[i].x>=a[i-1].x&&a[i].y>=a[i-1].y)) flag=1;//判断有没有重复减的情况。 if(!flag) { //加上重复减的情况 。 s=1; for(i=1;i<=n;) { for(j=i;j<=n&&a[i].x==a[j].x&&a[i].y==a[j].y;j++); s=s*p[j-i]%mod; i=j; } ans+=s; } s=1; //减去光按a[i].x的情况。 for(i=1;i<=n;) { for(j=i;j<=n&&a[i].x==a[j].x;j++); s=s*p[j-i]%mod; i=j; } ans-=s; sort(a+1,a+1+n,cmp2); s=1; //减去光按a[i].y的情况。 for(i=1;i<=n;) { for(j=i;j<=n&&a[i].y==a[j].y;j++); s=s*p[j-i]%mod; i=j; } ans-=s; printf("%lld\n",((ans%mod)+mod)%mod);//防止负数。 }
标签:names force flag define col ret point mod code
原文地址:https://www.cnblogs.com/2462478392Lee/p/11402790.html