bzoj1002题解

【题意分析】

  给你一张特殊的,被称为“轮状基”的无向图,求其生成树个数。

【解题思路】

引理:

  基尔霍夫矩阵:

基尔霍夫矩阵=度数矩阵-邻接矩阵(邻接矩阵权=两点连边数)

  Matrix-Tree定理:

对于任意一个无向图,其生成树个数为其基尔霍夫矩阵的任意一个余子式的行列式值。

算法一:

  直接暴力构图,用Matrix-Tree定理算出生成树个数,复杂度O(n^3),理论可过,但考虑到高精度。。

  附上一个算矩阵行列式的小公举工具。

算法二:

  听说这个图很特殊,那一定有一些特殊性质?

  先写出这个基尔霍夫矩阵的一般形态:

  答案就是他的任意一个代数余子式的行列式值,为了最简化问题,我们可以去掉第一行第一列:

  那么只要求这个矩阵的行列式值就可以了。

  我们先初等变换一下:

  这样答案就等于这个矩阵的行列式值前面加个符号,即乘上(-1)n-1

  寻找这个矩阵行列式计算的规律,发现对倒数第二行进行高斯消元:

  可得递推式组:

  • Fi=Gi-1+3*Fi-1
  • Gi=-Fi-1

  整理后即Fi=3*Fi-1-Fi-2(边界F1=-1,F2=-3)

  于是可以矩阵可以变换为这种形式:

  同理,对倒数第一行进行高斯消元,矩阵最终变为:

  其行列式为:(-1)n-2*f*(i-g*h/f)=(-1)n-2*(f*i-g*h)

  则原行列式值为:(-1)2n-3*(f*i-g*h)=g*h-f*i

  带入各函数,结合关于行列式的FH定理,展开得:Hn+Fn-1-2

  设原式=Rn,可得递推式:Rn=3*Rn-1-Rn-2+2(R1=2,R2=5)

  这就是答案递推式了,复杂度O(n)。

  恩,更详尽的证明,让vfk带你飞!

算法三:

  打表找规律!(听说这就是我当初把这题当成高精度练习题的理由)

  设Fi=3*Fi-2-Fi-4,则当i为奇数时,ansi=Fi2,当i为偶数时,ansi=5*Fi2

  复杂度O(n)

【参考程序】

//听说我写这题时我还没有听说过一个叫做Py的东西。。QAQ

//这个板子还有可能是错的。。QAQ

  1 #include<cstdio>
  2 #include<iostream>
  3 #include<cstring>
  4 #include<string>
  5 #include<algorithm>
  6 #include<stack>
  7 #define REP(I,start,end) for(int I=start;I<=end;I++)
  8 #define PER(I,start,end) for(int I=start;I>=end;I--)
  9 using namespace std;
 10 long long digiter=100000000ll;
 11 inline void init(long long initer)
 12 {
 13     digiter=initer;
 14 }
 15 struct bigNumber
 16 {
 17     int len;
 18     long long num[501];
 19     inline void operator =(long long T)
 20     {
 21         memset(num,0,sizeof(num));
 22         len=0;
 23         while(T)
 24         {
 25             num[++len]=T%digiter;
 26             T/=digiter;
 27         }
 28     }
 29     bool positive()
 30     {
 31         return len&&num[len]>0;
 32     }
 33     bool odd()
 34     {
 35         return num[1]&1;
 36     }
 37     inline bool operator ==(const bigNumber& T)const
 38     {
 39         if(len!=T.len)
 40             return false;
 41         REP(i,1,len)
 42             if(num[i]!=T.num[i])
 43                 return false;
 44         return true;
 45     }
 46     inline bool operator >(const bigNumber& T)const
 47     {
 48         if(len<T.len)
 49             return false;
 50         if(len>T.len)
 51             return true;
 52         PER(i,len,1)
 53         {
 54             if(num[i]<T.num[i])
 55                 return false;
 56             if(num[i]>T.num[i])
 57                 return true;
 58         }
 59         return false;
 60     }
 61     inline bool operator >=(const bigNumber& T)const
 62     {
 63         if(len<T.len)
 64             return false;
 65         if(len>T.len)
 66             return true;
 67         PER(i,len,1)
 68         {
 69             if(num[i]<T.num[i])
 70                 return false;
 71             if(num[i]>T.num[i])
 72                 return true;
 73         }
 74         return true;
 75     }
 76     inline bool operator <(const bigNumber& T)const
 77     {
 78         if(len>T.len)
 79             return false;
 80         if(len<T.len)
 81             return true;
 82         PER(i,len,1)
 83         {
 84             if(num[i]>T.num[i])
 85                 return false;
 86             if(num[i]<T.num[i])
 87                 return true;
 88         }
 89         return false;
 90     }
 91     inline bool operator <=(const bigNumber& T)const
 92     {
 93         if(len>T.len)
 94             return false;
 95         if(len<T.len)
 96             return true;
 97         PER(i,len,1)
 98         {
 99             if(num[i]>T.num[i])
100                 return false;
101             if(num[i]<T.num[i])
102                 return true;
103         }
104         return true;
105     }
106     inline void operator +=(const long long TT)
107     {
108         long long T=TT;
109         int i=1;
110         while(T)
111         {
112             num[i]+=T%digiter;
113             T/=digiter;
114             i++;
115         }
116         REP(i,1,len)
117         {
118             num[i+1]+=num[i]/digiter;
119             num[i]%=digiter;
120         }
121         while(num[len+1])
122             len++;
123     }
124     inline void operator -=(const long long TT)
125     {
126         long long T=TT;
127         int i=1;
128         while(T)
129         {
130             num[i]-=T%digiter;
131             T/=digiter;
132             i++;
133         }
134         REP(i,1,len)
135             while(num[i]<0ll)
136             {
137                 num[i+1]--;
138                 num[i]+=digiter;
139             }
140         while(len&&num[len]==0ll)
141             len--;
142     }
143     inline void operator *=(const long long T)
144     {
145         REP(i,1,len)
146             num[i]*=T;
147         REP(i,1,len)
148         {
149             num[i+1]+=num[i]/digiter;
150             num[i]%=digiter;
151         }
152         while(num[len+1])
153         {
154             len++;
155             num[len+1]+=num[len]/digiter;
156             num[len]%=digiter;
157         }
158     }
159     inline void operator /=(const long long T)
160     {
161         long long rest=0ll;
162         PER(i,len,1)
163         {
164             rest=rest*digiter+num[i];
165             num[i]=rest/T;
166             rest%=T;
167         }
168         while(len&&num[len]==0ll)
169             len--;
170     }
171 }f[101],three;
172 inline bigNumber operator +(const bigNumber A,const bigNumber B)
173 {
174     bigNumber C;
175     memset(C.num,0,sizeof(C.num));
176     C.len=max(A.len,B.len);
177     REP(i,1,C.len)
178         C.num[i]=A.num[i]+B.num[i];
179     REP(i,1,C.len)
180     {
181         C.num[i+1]+=C.num[i]/digiter;
182         C.num[i]%=digiter;
183     }
184     while(C.num[C.len+1])
185     {
186         C.len++;
187         C.num[C.len+1]+=C.num[C.len]/digiter;
188         C.num[C.len]%=digiter;
189     }
190     return C;
191 }
192 inline bigNumber operator -(const bigNumber A,const bigNumber B)
193 {
194     bigNumber C;
195     memset(C.num,0,sizeof(C.num));
196     C.len=max(A.len,B.len);
197     REP(i,1,C.len)
198         C.num[i]=A.num[i]-B.num[i];
199     REP(i,1,C.len)
200         while(C.num[i]<0)
201         {
202             C.num[i+1]--;
203             C.num[i]+=digiter;
204         }
205     while(C.len&&C.num[C.len]==0)
206         C.len--;
207     return C;
208 }
209 inline bigNumber operator *(const bigNumber A,const bigNumber B)
210 {
211     bigNumber C;
212     memset(C.num,0,sizeof(C.num));
213     C.len=A.len+B.len-1;
214     REP(i,1,A.len)
215         REP(j,1,B.len)
216         {
217             C.num[i+j-1]+=A.num[i]*B.num[j];
218             C.num[i+j]+=C.num[i+j-1]/digiter;
219             C.num[i+j-1]%=digiter;
220         }
221     while(C.num[C.len+1])
222     {
223         C.len++;
224         C.num[C.len+1]+=C.num[C.len]/digiter;
225         C.num[C.len]%=digiter;
226     }
227     while(C.num[C.len]==0)
228         C.len--;
229     return C;
230 }
231 inline long long operator %(const bigNumber A,const long long B)
232 {
233     long long T=0;
234     PER(i,A.len,1)
235         T=(T*digiter+A.num[i])%B;
236     return T;
237 }
238 inline bigNumber gcd(const bigNumber AA,const bigNumber BB)
239 {
240     bigNumber C,A=AA,B=BB;
241     while(B.positive())
242     {
243         C=A;
244         while(C>=B)
245             C=C-B;
246         A=B;
247         B=C;
248     }
249     return A;
250 }
251 inline bigNumber sqr(const bigNumber T)
252 {
253     return T*T;
254 }
255 inline bigNumber power(const bigNumber A,const int B)
256 {
257     stack<bool> isODD;
258     while(!isODD.empty())
259         isODD.pop();
260     int tmp=B;
261     while(tmp)
262     {
263         isODD.push(tmp&1);
264         tmp>>=1;
265     }
266     bigNumber C;
267     C=1ll;
268     while(!isODD.empty())
269     {
270         C=sqr(C);
271         if(isODD.top())
272             C=C*A;
273         isODD.pop();
274     }
275     return C;
276 }
277 inline bigNumber fact(int n)
278 {
279     bigNumber ans;
280     ans=1ll;
281     REP(i,2,n)
282         ans*=i;
283     return ans;
284 }
285 inline bigNumber max(const bigNumber A,const bigNumber B)
286 {
287     if(A>B)
288         return A;
289     return B;
290 }
291 inline bigNumber min(const bigNumber A,const bigNumber B)
292 {
293     if(A<B)
294         return A;
295     return B;
296 }
297 inline void scan(bigNumber& T)
298 {
299     memset(T.num,0,sizeof(T.num));
300     if(digiter==10ll)
301     {
302         T.len=0;
303         char ch=getchar();
304         while(ch<‘0‘||ch>‘9‘)
305             ch=getchar();
306         while(ch>=‘0‘&&ch<=‘9‘)
307         {
308             T.num[++T.len]=ch-‘0‘;
309             ch=getchar();
310         }
311         REP(i,1,T.len>>1)
312             swap(T.num[i],T.num[T.len-i+1]);
313     }
314     else
315     {
316         string st;
317         cin>>st;
318         T.len=1;
319         long long tmp=1ll;
320         PER(i,st.length()-1,0)
321         {
322             T.num[T.len]+=(st[i]-‘0‘)*tmp;
323             tmp*=10ll;
324             if(tmp==digiter)
325             {
326                 T.len++;
327                 tmp=1ll;
328             }
329         }
330         if(tmp==1ll)
331             T.len--;
332     }
333 }
334 inline void print(const bigNumber T)
335 {
336     if(T.len==0)
337     {
338         putchar(‘0‘);
339         return;
340     }
341     if(digiter==10ll)
342         PER(i,T.len,1)
343             putchar(char(T.num[i])+‘0‘);
344     else
345     {
346         printf("%lld",T.num[T.len]);
347         PER(i,T.len-1,1)
348         {
349             long long tmp=digiter/10ll;
350             while(tmp)
351             {
352                 printf("%lld",T.num[i]/tmp%10ll);
353                 tmp/=10ll;
354             }
355         }
356     }
357 }
358 int n;
359 int main()
360 {
361     scanf("%d",&n);
362     f[1]=1ll;
363     f[2]=1ll;
364     f[3]=4ll;
365     f[4]=3ll;
366     three=3ll;
367     REP(i,5,n)
368         f[i]=f[i-2]*three-f[i-4];
369     f[n]=sqr(f[n]);
370     if(~n&1)
371         f[n]*=5ll;
372     print(f[n]);
373     return 0;
374 }

  和Py比较一下。。

1 if __name__=="__main__":
2     n,last,ans=input(),1,5
3     if n<2:
4         print 2
5     else:
6         for i in xrange(n-2):
7             ans,last=3*ans-last+2,ans
8         print ans

QAQ

时间: 2024-11-11 08:51:41

bzoj1002题解的相关文章

[bzoj1002][FJOI2007]轮状病毒-题解[基尔霍夫矩阵][高精度][递推]

Description 轮状病毒有很多变种,所有轮状病毒的变种都是从一个轮状基产生的.一个N轮状基由圆环上N个不同的基原子和圆心处一个核原子构成的,2个原子之间的边表示这2个原子之间的信息通道.如下图所示 N轮状病毒的产生规律是在一个N轮状基中删去若干条边,使得各原子之间有唯一的信息通道,例如共有16个不同的3轮状病毒,如下图所示 现给定n(N<=100),编程计算有多少个不同的n轮状病毒 Input 第一行有1个正整数n Output 计算出的不同的n轮状病毒数输出 Sample Input

bzoj1002[FJOI2007]轮状病毒

bzoj1002[FJOI2007]轮状病毒 题意: N轮状病毒的产生规律是在一个N轮状基中删去若干条边,使得各原子之间有唯一的信息通道,例如共有16个不同的3轮状病毒,如下图所示 现给定n,计算有多少个不同的n轮状病毒.N<=100 题解: 公式:f[i]=f[i-1]*3-f[i-2]+2,i≥3,f[1]=1,f[2]=5.(我承认我是抄的QAQ因为我根本不懂什么矩阵树定理~ 又是高精度,又被我用python水掉了…… 代码: 1 n=int(raw_input()) 2 a=1 3 b=

BZOJ1002

传送门:BZOJ1002 似乎做法挺多,不过我并不懂得基于连通性的动态规划,于是只能做纯数学解法. 我们需要以下知识: Kirchhoff Matrix Tree定理: 设G为无向图,取E为图G的度数矩阵,F为图G的邻接矩阵 称矩阵E?F为图G的Kirchhoff矩阵R,任取与R同构的行列式R′的任意一个n?1阶主子式Q,其值为图G的生成树个数. 这个定理不是显然的,但我们在这里不证,因为它与本题的讨论无关. 取中心点为0号点,其余点按顺时针顺序标为1234-n,则有 R=???????????

洛谷 P1079 Vigen&#232;re 密码 题解

此文为博主原创题解,转载时请通知博主,并把原文链接放在正文醒目位置. 题目链接:https://www.luogu.org/problem/show?pid=1079 题目描述 16 世纪法国外交家 Blaise de Vigenère 设计了一种多表密码加密算法――Vigenère 密 码.Vigenère 密码的加密解密算法简单易用,且破译难度比较高,曾在美国南北战争中为 南军所广泛使用. 在密码学中,我们称需要加密的信息为明文,用 M 表示:称加密后的信息为密文,用 C 表示:而密钥是一种

8.8联考题解

今天的T1让我怀疑我是不是在做奥赛题--这考的是什么知识点啊这个,会不会用绝对值函数? Evensgn 的债务 时间限制: 1 Sec  内存限制: 128 MB 题目描述 Evensgn 有一群好朋友,他们经常互相借钱.假如说有三个好朋友A,B,C.A 欠 B 20 元,B 欠 C 20 元,总债务规模为 20+20=40 元.Evensgn 是个追求简约的人,他觉得这样的债务太繁杂了.他认为,上面的债务可以完全等价为 A 欠C20 元,B 既不欠别人,别人也不欠他.这样总债务规模就压缩到了 

POJ 2533 - Longest Ordered Subsequence(最长上升子序列) 题解

此文为博主原创题解,转载时请通知博主,并把原文链接放在正文醒目位置. 题目链接:http://poj.org/problem?id=2533 Description A numeric sequence of ai is ordered if a1 < a2 < ... < aN. Let the subsequence of the given numeric sequence (a1, a2, ..., aN) be any sequence (ai1, ai2, ..., aiK)

(leetcode题解)Pascal&#39;s Triangle

Pascal's Triangle  Given numRows, generate the first numRows of Pascal's triangle. For example, given numRows = 5,Return [ [1], [1,1], [1,2,1], [1,3,3,1], [1,4,6,4,1] ] 题意实现一个杨辉三角. 这道题只要注意了边界条件应该很好实现出来,C++实现如下 vector<vector<int>> generate(int

2017ZZUACM省赛选拔试题部分题解----谨以纪念我这卡线滚粗的美好经历

写在前面: 其实心里有些小小的不爽又有点小小的舒畅,为啥捏?不爽当然是因为没被选拔上啦,舒畅捏则是因为没被选拔上反而让自己警醒,学长也提点很多很多."沉下去,然后一战成名"学长如是对我说,我很开心.其实这完全算不算是题解,只是我个人的一些小想法而已.而且到现在还有一题不会...让自己长点记性吧. 题目 A :聪明的田鼠 Time Limit: 1 Sec Memory Limit: 128 MB Description 田鼠MIUMIU来到了一片农田,农田可以看成是一个M*N个方格的矩

LeetCode-001题解

此题目摘自LeetCode001 Given an array of integers, find two numbers such that they add up to a specific target number. The function twoSum should return indices of the two numbers such that they add up to the target, where index1 must be less than index2.