【题意分析】
给你一张特殊的,被称为“轮状基”的无向图,求其生成树个数。
【解题思路】
引理:
基尔霍夫矩阵:
基尔霍夫矩阵=度数矩阵-邻接矩阵(邻接矩阵权=两点连边数)
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