9.27考试 SD_le NOIP模拟题 第三题 建造游乐场题解
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了9.27考试 SD_le NOIP模拟题 第三题 建造游乐场题解相关的知识,希望对你有一定的参考价值。
这道题当时没读完题时脑部了无数种问法,然而最后还是猝不及防。一开始还以为是结论题,然而死也退不出来,就先去打第二题了。然后在想这道题时,我想到的是这样的思路(由于当时时间紧迫,尚未完善):
我每次向图中增加两个点,那么这两个点对于所有入度为偶数的点是否连接一定是一致的,如果这两个点相连,那么如果使他们分别和一个入度为单数的点相连,那么他们就是新的入度为单数的点,其他情况就不叙述了,太多了。还不是正解。
由于最后时间太紧迫了,我不得不打暴力去保分,结果还好丢人好丢人的打错了……
正解其实还是挺有意思的,不知道怎么去概括,但个人觉得我之前的想法和他有一丝丝的相似。
我们可以明确这样一个性质,假设有n各点,他们无重边,无自环,但不一定连通,那么如果我再去加一个点,去让他联通,那么方案一定存在且只有一种于是我们设g[i]为有i各点让他们满足无重边,无自环,联通的情况数,就是2^C(i-1,2)即每两个点之间是否联通的累乘。
说这个有什么用呢,我们可以利用容斥原理去算出f[i]即有i个点的欧拉图的方案。
f[i]=g[i]-∑(f[j]*g[i-j]*C(i-1,j-1)),右半侧即为1号点在有j点的联通块内,向i-j的不一定满足欧拉图的另一个块内连边且这两个块之间无连边的方案数,C(i-1,j-1)即为那些点在一侧的方案数,可以证明这样无重复。
最后的答案就是f[n]*C(n,2),为什么会乘以一个C(n,2)呢,因为我们求出来的只是欧拉图的个数,对于这个图中的任意两个点,如果他们连边,那么把这条边拆去就是题目要求的需要连一条边才是欧拉图的图,如果两个点之间没连边,把这条边连上就是需要拆边才符合条件的图。
顺便吐槽一句,为什么大佬们打完比赛都不打题解啊,想看一看他们考试的心路借鉴一下怎么那么难呢?
1 #include<iostream> 2 #include<cstdlib> 3 #include<cstdio> 4 #include<cstring> 5 #include<queue> 6 #include<algorithm> 7 #include<cmath> 8 #include<map> 9 #include<set> 10 #define N 2005 11 using namespace std; 12 long long n,p=1000000007; 13 long long c[N][N],f[N],g[N]; 14 void init() 15 { 16 c[1][0]=c[1][1]=1; 17 for(int i=2;i<=N-2;i++) 18 { 19 for(int j=0;j<=i;j++) 20 { 21 c[i][j]=c[i-1][j]+c[i-1][j-1]; 22 c[i][j]%=p; 23 } 24 } 25 } 26 long long ksm(long long a,long long x) 27 { 28 long long ans=1; 29 while(x) 30 { 31 if(x&1) 32 { 33 ans*=a; 34 ans%=p; 35 } 36 a*=a; 37 a%=p; 38 x>>=1; 39 } 40 return ans; 41 } 42 int main() 43 { 44 init(); 45 scanf("%lld",&n); 46 47 for(int i=3;i<=n;i++) 48 { 49 g[i]=ksm(2ll,c[i-1][2]); 50 } 51 g[1]=g[2]=1; 52 f[1]=1; 53 for(int i=3;i<=n;i++) 54 { 55 f[i]=g[i]; 56 for(int j=1;j<i;j++) 57 { 58 f[i]-=(f[j]*g[i-j]%p*c[i-1][j-1]%p)%p; 59 f[i]%=p; 60 if(f[i]<0)f[i]+=p; 61 } 62 } 63 printf("%lld\\n",f[n]*c[n][2]%p); 64 return 0; 65 }
以上是关于9.27考试 SD_le NOIP模拟题 第三题 建造游乐场题解的主要内容,如果未能解决你的问题,请参考以下文章