[loj3056][hnoi2019]多边形
前言
模數打錯導致在模擬賽時變成40分
題目相關
鏈接
題目大意
給定一個多邊形的三角劃分
定義一個旋轉操作為對于四個有邊相連的點a<b<c<da<b<c<da<b<c<d,原本a?ca\leftrightarrow ca?c連邊,旋轉后b?db\leftrightarrow db?d連邊
給定一幅nnn個點的多邊形三角劃分圖,求至少旋轉多少次才能使這個圖內不能再旋轉,并輸出這樣旋轉的方案數
給出的圖分為兩種,一種是原圖,還有一種是在原圖中給出一條邊a?ca\leftrightarrow ca?c,將其旋轉得到的圖(顯然一條邊的旋轉唯一),詢問圖的數量為mmm
數據范圍
n,m≤100000n,m\le100000n,m≤100000
題解
首先定義did_idi?為iii號點的度數(不包含多邊形上的邊)
首先考慮終止狀態,觀察樣例,我們發現所有邊都連向nnn號點時就不能再轉了
我們發現每次肯定能將一條端點中不含nnn的邊轉到含nnn
具體操作是選定一條邊a?ba\leftrightarrow ba?b,其兩側的三角形分別為Δabc\Delta abcΔabc和Δabn\Delta abnΔabn這樣就可以把邊轉為c?nc\leftrightarrow nc?n
我們發現這樣一來,第一問的答案就是n?3?dnn-3-d_nn?3?dn?
我們考慮第二問,首先,我們發現邊的可旋轉順序構成的拓撲圖是一棵樹(這一點畫畫圖就知道了)
然后我們考慮方案數如何計算
我們仔細想發現這是經典套路:[loj6391][THUPC2018]淘米神的樹(Tommy)
我們考慮一棵樹的子樹方案數方案數(這棵子樹的根一定要第一個做,剩下的按子樹內部考慮即可)
ansu=(sizeu?1)!∏fav=uansvsizev!ans_u=(size_u-1)!\prod_{fa_v=u}\frac{ans_v}{size_v!}ansu?=(sizeu??1)!fav?=u∏?sizev?!ansv??
進行整理
ansu=(sizeu?1)!∏fav=usizev!∏fav=uansvans_u=\frac{(size_u-1)!}{\prod_{fa_v=u}size_v!}\prod_{fa_v=u}{ans_v}ansu?=∏fav?=u?sizev?!(sizeu??1)!?fav?=u∏?ansv?
根節點額外考慮,根節點是
ansroot=sizeroot!∏fav=rootansvsizev!ans_{root}=size_{root}!\prod_{fa_v=root}\frac{ans_v}{size_v!}ansroot?=sizeroot?!fav?=root∏?sizev?!ansv??
代入,我們發現每個節點都是一個節點的兒子,也是一個自己,這樣的話每個節點的貢獻就是(sizeu?1)!sizeu=1sizeu\frac{(size_u-1)!}{size_u}=\frac1{size_u}sizeu?(sizeu??1)!?=sizeu?1?
ansroot=sizeroot!∏u≠rootsizeuans_{root}=\frac{size_{root}!}{\prod_{u\neq root} size_u}ansroot?=∏u??=root?sizeu?sizeroot?!?
我們發現一條邊u?vu\leftrightarrow vu?v代表節點的size就是∣u?v∣?1|u-v|-1∣u?v∣?1
設ans1ans_1ans1?為第一問的答案,ans2ans_2ans2?為第二問的答案
即ans2=ans1!∏u?v,u≠n,v≠n∣u?v∣?1ans_2=\frac{ans_1!}{\prod_{u\leftrightarrow v,u\neq n,v\neq n}|u-v|-1}ans2?=∏u?v,u??=n,v??=n?∣u?v∣?1ans1?!?
我們發現這個很好維護,只要找到一次旋轉從哪條邊轉到了哪條邊即可,用個set維護一下每個點的出邊,然后在set中找連邊目標點的編號相鄰元素就是了
代碼
代碼很清真
#include<cstdio> #include<cctype> #include<algorithm> #include<set> #include<vector> typedef long long ll; #define rg register template <typename T> inline void read(T&x){char cu=getchar();x=0;bool fla=0;while(!isdigit(cu)){if(cu=='-')fla=1;cu=getchar();}while(isdigit(cu))x=x*10+cu-'0',cu=getchar();if(fla)x=-x;} template <typename T> inline void printe(const T x){if(x>=10)printe(x/10);putchar(x%10+'0');} template <typename T> inline void print(const T x){if(x<0)putchar('-'),printe(-x);else printe(x);} template <typename T> inline T gcd(const T a,const T b){if(!b)return a;return gcd(b,a%b);} template <typename T> inline T min(const T a,const T b){return a<b?a:b;} template <typename T> inline T abs(const T a){return a>0?a:-a;} const int maxn=100001,mod=1000000007; int W,n,m,d[maxn]; std::set<int>e[maxn]; ll pow(ll x,ll y) {ll res=1;for(;y;y>>=1,x=x*x%mod)if(y&1)res=res*x%mod;return res; } ll ans,fac[maxn],inv[maxn]; ll C(const int n,const int m){return fac[n]*inv[m]%mod*inv[n-m]%mod;} void calc() {print(n-3-d[n]);if(W)putchar(' '),print(fac[n-3-d[n]]*pow(ans,mod-2)%mod);putchar('\n'); } inline void del(const int u,const int v) {d[u]--,d[v]--;if(u!=n&&v!=n)ans=ans*pow(abs(u-v)-1ll,mod-2)%mod; } inline void add(const int u,const int v) {d[u]++,d[v]++;if(u!=n&&v!=n)ans=ans*(abs(u-v)-1)%mod; } int main() { // freopen("polygon.in","r",stdin);freopen("polygon.out","w",stdout);fac[0]=1;for(rg int i=1;i<=100000;i++)fac[i]=fac[i-1]*i%mod;inv[100000]=pow(fac[100000],mod-2);for(rg int i=100000;i>=1;i--)inv[i-1]=inv[i]*i%mod;ans=1;read(W),read(n);for(rg int i=1;i<=n-3;i++){int u,v;read(u),read(v);e[u].insert(v),e[v].insert(u);add(u,v);}e[n].insert(1),e[1].insert(n);for(rg int i=1;i<n;i++)e[i].insert(i+1),e[i+1].insert(i);calc();read(m);for(rg int i=1;i<=m;i++){int a,b,na,nb;read(a),read(b);del(a,b);std::set<int>::iterator Pos=e[a].find(b),Posl,Posr;Posl=Pos,Posl--;Posr=Pos,Posr++;na=*Posl,nb=*Posr;add(na,nb);calc();del(na,nb);add(a,b);}return 0; }總結
要想到拓撲的結果是一棵樹,然后推一波式子就好了
好像還可以用splay搞,聽說本質相同
總結
以上是生活随笔為你收集整理的[loj3056][hnoi2019]多边形的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: codeforces contest 1
- 下一篇: Two Merged Sequences