• [HNOI2019]多边形


    [HNOI2019]多边形

    传送门

    Luogu

    Solution

    可以说是Day1最简单的题目了.
    首先( ext{Orz yyb}),希望(yyb)高考顺利.
    首先注意到((a,c))对应着唯一一种方法分解,考虑与(n)相连的点将多边形分成了多个形如([l,r])的区间.
    每一个区间互相独立,考虑对于一个区间求解.
    在一个区间内,显然只有一个点可以进行分解,不妨令它为(p),此时可以分治求解.
    然后现在每一次操作就形成了一颗二叉树,考虑合并就是把两个不相关的子树按照顺序任意操作,即(prod_{i}inom{siz_ls+siz_rs}{siz_ls}).不同区间的合并同理.
    考虑提前完成一次操作:

    1. 如果是第一次操作后就和(n)相连了,那么直接删除他的贡献然后把他的儿子的贡献加入答案.
    2. 如果不是上述操作,那么按照(rotate)那样旋转后删除增加贡献即可.

    关于(2)可以自己画图手玩一下,有利于对于题解的理解.

    代码

    #include<stdio.h>
    #include<stdlib.h>
    #include<string.h>
    #include<math.h>
    #include<algorithm>
    #include<queue>
    #include<set>
    #include<map>
    #include<iostream>
    using namespace std;
    #define re register
    #define ll long long
    inline int gi()
    {
    	int f=1,sum=0;char ch=getchar();
    	while(ch>'9' || ch<'0'){if(ch=='-')f=-1;ch=getchar();}
    	while(ch>='0' && ch<='9'){sum=(sum<<3)+(sum<<1)+ch-'0';ch=getchar();}
    	return f*sum;
    }
    const int N=400010,Mod=1e9+7;
    int n,fac[N],ifac[N],inv[N],tot,siz[N],ch[N][2],fa[N],rt[N],ans=1;
    vector<int>G[N];map<pair<int,int>,int>M;
    int C(int x,int y){return 1ll*fac[x]*ifac[y]%Mod*ifac[x-y]%Mod;}
    int invC(int x,int y){return 1ll*ifac[x]*fac[y]%Mod*fac[x-y]%Mod;}
    int merge(int x,int y){return C(x+y,y);}
    int invmerge(int x,int y){return invC(x+y,y);}
    void divide(int &x,int ff,int l,int r)
    {
    	if(l+1>=r)return;x=++tot;fa[x]=ff;siz[x]=1;
    	M[make_pair(l,r)]=x;
    	int p=lower_bound(G[r].begin(),G[r].end(),l+1)-G[r].begin();p=G[r][p];
    	divide(ch[x][0],x,l,p);divide(ch[x][1],x,p,r);
    	ans=1ll*ans*merge(siz[ch[x][0]],siz[ch[x][1]])%Mod;
    	siz[x]=siz[ch[x][0]]+siz[ch[x][1]]+1;
    }
    int opt;
    void print(int cnt,int ans){printf("%d",cnt);if(opt)printf(" %d",ans);putchar('
    ');}
    int main()
    {
    	opt=gi();
    	n=gi();fac[0]=inv[0]=inv[1]=ifac[0]=1;
    	for(int i=1;i<=n<<1;i++)fac[i]=1ll*fac[i-1]*i%Mod;
    	for(int i=2;i<=n<<1;i++)inv[i]=1ll*(Mod-Mod/i)*inv[Mod%i]%Mod;
    	for(int i=1;i<=n<<1;i++)ifac[i]=1ll*ifac[i-1]*inv[i]%Mod;
    	for(int i=1;i<=n-3;i++)
    	{
    		int x=gi(),y=gi();
    		G[x].push_back(y);G[y].push_back(x);
    	}
    	for(int i=2;i<n;i++)G[i].push_back(i-1),G[i].push_back(i+1);
    	G[1].push_back(n);G[1].push_back(2);G[n].push_back(1);G[n].push_back(n-1);
    	for(int i=1;i<=n;i++)sort(G[i].begin(),G[i].end());
    	for(int i=0,l=G[n].size();i<l-1;i++)divide(rt[i],0,G[n][i],G[n][i+1]);
    	int sz=0,cnt=n-1-G[n].size();
    	for(int i=0,l=G[n].size();i<l-1;i++)ans=1ll*ans*merge(sz,siz[rt[i]])%Mod,sz+=siz[rt[i]];
    	print(cnt,ans);
    	int m=gi();
    	while(m--)
    	{
    		int a=gi(),b=gi();if(a>b)swap(a,b);
    		int p=M[make_pair(a,b)];
    		int pcnt=cnt-(!fa[p]),pans=ans;
    		if(fa[p])
    		{
    			int ff=fa[p],k=ch[ff][1]==p;
    			pans=1ll*pans*invmerge(siz[ch[ff][0]],siz[ch[ff][1]])%Mod;
    			pans=1ll*pans*invmerge(siz[ch[p][0]],siz[ch[p][1]])%Mod;
    			pans=1ll*pans*merge(siz[ch[ff][k^1]],siz[ch[p][k^1]])%Mod;
    			pans=1ll*pans*merge(siz[ff]-siz[p]+siz[ch[p][k^1]],siz[ch[p][k]])%Mod;
    		}
    		else
    		{
    			pans=1ll*pans*invmerge(siz[ch[p][0]],siz[ch[p][1]])%Mod;
    			pans=1ll*pans*invmerge(sz-siz[p],siz[p])%Mod;
    			pans=1ll*pans*merge(sz-siz[p],siz[ch[p][0]])%Mod;
    			pans=1ll*pans*merge(sz-siz[p]+siz[ch[p][0]],siz[ch[p][1]])%Mod;
    		}
    		print(pcnt,pans);
    	}
    	return 0;
    }
    
  • 相关阅读:
    Spark Streaming 中管理 Kafka Offsets 的几种方式
    Kafka 在华泰证券的探索与实践
    Kafka 客户端是如何找到 leader 分区的
    关于Java中如何判断字符串是否为json格式
    关于JAVA递归遍历树级菜单结构
    关于JDK8 三种时间获取方法以及日期加减
    关于在Java里面,时间的一些业务
    关于Java的IO通信
    关于git同时提交到2个仓库gitee github
    关于JVM——工具(二)
  • 原文地址:https://www.cnblogs.com/fexuile/p/12359528.html
Copyright © 2020-2023  润新知