1. 程式人生 > >jzojs 5384. 【NOIP2017提高A組模擬9.23】四維世界

jzojs 5384. 【NOIP2017提高A組模擬9.23】四維世界

Description
眾所周知,我們常感受的世界是三維的。
Polycarp突然對四維空間產生了興趣,他想對四維空間進行一些研究。但是在此之前,他必須先對三維世界瞭解透徹。
於是Polycarp決定從零維,也就是一個點,開始他的研究。我們把一個點放在三維空間中,Polycarp把這個點視為原點,並確定了三個正方向。他可以把這個點往三個方向之一拉伸一個單位,那麼這個點就變為了一維的一條長度為一的線段。然後如果他把這條線段往另一方向拉伸一個單位,那麼這條線就變為了二維的一個矩形。如果繼續拉伸可能就會進入三維世界,也就是變為直四稜柱。
Polycarp認為矩形、線段甚至點都可以看作某一維或某幾維為豐的直四稜柱。
現在Polycarp想演示把一個點一步一步拉伸為邊長為n的正六面體的過程,但他缺失了m種形態的直四稜柱模具(Polycarp擁有其他的所有直四稜柱模具),他想知道共有多少種演示方案。
Polycarp的演示過程需要每拉伸一個單位時對應形態的直四稜柱。
因為方案數很大,所以輸出答案對10^9+7的結果。

Input
從檔案poly.in中讀入資料。
第一行兩個整數n;m,分別表示直四稜柱的邊長和他缺失的模具數量。
接下來m行,第i行三個整數x; y; z,表示第i個缺失模具的長、寬、高。

Output
輸出到檔案poly.out中
一個整數,即答案。

Sample Input
2 3
1 0 1
1 1 1
0 2 0

Sample Output
36

100%,n<=10^5,m<=5000

不多說,直接暴力模擬即可。

#include<cstdio>
#include<algorithm>
#define ll long long #define mo 1000000007 using namespace std; struct node{int x,y,z;}a[5010]; ll jc[300010],nyj[100010],f[5010]; int n,m; inline int read() { int x=0; char c=getchar(); while (c<'0' || c>'9') c=getchar(); while (c>='0' && c<='9') x=x*10+c-48,c=getchar(); return x; } ll ny(ll x) {
ll s=1,y=mo-2; while (y) { if (y & 1) s=s*x%mo; x=x*x%mo;y>>=1; } return s; } int cmp(node x,node y) {return x.x==y.x ? ((x.y==y.y) ? x.z<y.z:x.y<y.y):x.x<y.x;} ll doit(int x,int y,int z) {return jc[x+y+z]*nyj[x]%mo*nyj[y]%mo*nyj[z]%mo;} int main() { freopen("poly.in","r",stdin); freopen("poly.out","w",stdout); jc[0]=jc[1]=1;for (int i=2;i<=300000;i++) jc[i]=jc[i-1]*i%mo; nyj[100000]=ny(jc[100000]); for (int i=99999;i>=0;i--) nyj[i]=nyj[i+1]*(i+1)%mo; n=read(),m=read(); for (int i=1;i<=m;i++) a[i].x=read(),a[i].y=read(),a[i].z=read(); a[++m]=(node){n,n,n}; sort(a+1,a+m+1,cmp); for (int i=1;i<=m;i++) { f[i]=doit(a[i].x,a[i].y,a[i].z); for (int j=1;j<i;j++) if (a[i].y>=a[j].y && a[i].z>=a[j].z) f[i]=(f[i]-f[j]*doit(a[i].x-a[j].x,a[i].y-a[j].y,a[i].z-a[j].z)+mo)%mo; } printf("%lld\n",f[m]); return 0; }