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

JZOJ5384. 【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

題解

題目可以轉化為:在一個三維的空間裡面,從(0,0,0)走到(n,n,n),且不經過一些特定點的方案數。

先考慮沒有任何限制的情況:方案數就3*n!。
如果有限制,那我們就減去經過這個點的方案數,即(0,0,0)走到

xiyizi *xiyizi走到(n,n,n)。
這樣就能夠推出一個dp。

code

#include<queue>
#include<cstdio>
#include<iostream>
#include<algorithm>
#include <cstring>
#include <string.h>
#include <cmath>
#include <math.h>
#define ll long long
#define N 100003
#define db double
#define P putchar #define G getchar #define mo 1000000007 using namespace std; char ch; void read(int &n) { n=0; ch=G(); while((ch<'0' || ch>'9') && ch!='-')ch=G(); ll w=1; if(ch=='-')w=-1,ch=G(); while('0'<=ch && ch<='9')n=(n<<3)+(n<<1)+ch-'0',ch=G(); n*=w; } int max(int a,int b){return a>b?a:b;} int min(int a,int b){return a<b?a:b;} void write(ll x) { if(x>9) write(x/10); P(x%10+'0'); } struct node { int x,y,z; }a[N]; int n,m; ll jc[N*3],ny[N*3],f[N]; ll ksm(ll x,int y) { ll s=1; while(y) { if(y&1)s=s*x%mo; x=x*x%mo; y>>=1; } return s; } bool cmp(node a,node b) { return a.x<b.x || (a.x==b.x && a.y<b.y) || (a.x==b.x && a.y==b.y && a.z<b.z); } ll get(int x,int y,int z) { return jc[x+y+z]*ny[x]%mo*ny[y]%mo*ny[z]%mo; } int main() { freopen("poly.in","r",stdin); freopen("poly.out","w",stdout); read(n);read(m); jc[0]=ny[0]=1; for(int i=1;i<=n*3;i++) jc[i]=jc[i-1]*i%mo,ny[i]=ksm(jc[i],mo-2); for(int i=1;i<=m;i++) read(a[i].x),read(a[i].y),read(a[i].z); m++; a[m].x=a[m].y=a[m].z=n; sort(a+1,a+1+m,cmp); for(int i=1;i<=m;i++) { f[i]=get(a[i].x,a[i].y,a[i].z); for(int j=1;j<i;j++) if(a[j].x<=a[i].x && a[j].y<=a[i].y && a[j].z<=a[i].z) f[i]=(f[i]-f[j]*get(a[i].x-a[j].x,a[i].y-a[j].y,a[i].z-a[j].z)%mo+mo)%mo; } write(f[m]); }