BZOJ 1002 轮状病毒 矩阵树定理
题目链接:
https://www.lydsy.com/JudgeOnline/problem.php?id=1002
题目大意:
给定n(N<=100),编程计算有多少个不同的n轮状病毒
思路:
大部分题解都是直接一个递推公式,具体得来的方法由矩阵树定理可以求得。
只是求矩阵的行列式的时候比较复杂。
具体证明过程:http://vfleaking.blog.163.com/blog/static/17480763420119685112649/
需要高精度
1 #include <bits/stdc++.h> 2 #define IOS ios::sync_with_stdio(false);//不可再使用scanf printf 3 #define Max(a, b) (a) > (b) ? (a) : (b) 4 #define Min(a, b) (a) < (b) ? (a) : (b) 5 #pragma comment(linker, "/STACK:102400000,102400000") 6 using namespace std; 7 8 typedef long long ll; 9 const int mod = 1e9 + 7; 10 const int maxn = 1000000 + 10; 11 12 #define MAXN 9999 13 #define MAXSIZE 1000 14 #define DLEN 4 15 //如果位数特别大,可以把数组a放大,也可以把MAXN多加几个9,同时DLEN = 9的个数 后者方法会更快 16 class BigNum { 17 private: 18 public: 19 ll a[1000]; //可以控制大数的位数 20 int len; //大数长度 21 22 BigNum() {len = 1;memset(a,0,sizeof(a));} //构造函数 23 BigNum(const ll); //int 构造函数 24 BigNum(const char*); //字符串 构造函数 25 BigNum(const string); //string 构造函数 26 BigNum(const BigNum &); //拷贝构造函数 27 BigNum &operator=(const BigNum &);//重载赋值运算符 28 29 friend istream& operator >> (istream&, BigNum&);//重载输入运算符 30 friend ostream& operator << (ostream&, BigNum&);//重载输出运算符 31 32 BigNum operator + (const BigNum &) const;//重载加法 33 BigNum operator - (const BigNum &) const;//重载减法 34 BigNum operator * (const BigNum &) const;//重载乘法 35 BigNum operator / (const ll &) const; //重载除法 int 36 BigNum operator ^ (const ll &) const; //n次方 37 ll operator % (const ll &) const; //对int 取模 38 39 bool operator > (const BigNum & T)const; //比较大小 40 bool operator > (const ll & t)const; 41 bool operator < (const BigNum & T)const; 42 bool operator < (const ll & t)const; 43 bool operator == (const BigNum & T)const; 44 bool operator == (const ll & t)const; 45 46 void print(); //输出大数 47 }; 48 BigNum::BigNum(const ll b) //int 构造函数 49 { 50 ll c, d = b; 51 len = 0; 52 memset(a,0,sizeof(a)); 53 while(d > MAXN) 54 { 55 c = d - (d / (MAXN + 1)) * (MAXN + 1); 56 d = d / (MAXN + 1); a[len++] = c; 57 } 58 a[len++] = d; 59 } 60 BigNum::BigNum(const char*s)//字符串 构造函数 61 { 62 ll t, k, index, l; 63 memset(a,0,sizeof(a)); 64 l = strlen(s); 65 len = l / DLEN; 66 if(l % DLEN)len++; 67 index=0; 68 for(int i = l - 1; i >= 0;i -= DLEN) 69 { 70 t = 0; k = i - DLEN + 1; 71 if(k < 0)k = 0; 72 for(int j = k; j <= i; j++) 73 t = t * 10 + s[j] - '0'; 74 a[index++]=t; 75 } 76 } 77 BigNum::BigNum(const string s)//字符串 构造函数 78 { 79 ll t, k, index, l; 80 memset(a,0,sizeof(a)); 81 l = s.size(); 82 len = l / DLEN; 83 if(l % DLEN)len++; 84 index=0; 85 for(int i = l - 1; i >= 0;i -= DLEN) 86 { 87 t = 0; k = i - DLEN + 1; 88 if(k < 0)k = 0; 89 for(int j = k; j <= i; j++) 90 t = t * 10 + s[j] - '0'; 91 a[index++]=t; 92 } 93 } 94 BigNum::BigNum(const BigNum & T) : len(T.len)//拷贝构造函数 95 { 96 memset(a,0,sizeof(a)); 97 for(int i = 0 ; i < len ; i++)a[i] = T.a[i]; 98 } 99 BigNum & BigNum::operator = (const BigNum & n)//重载赋值运算符 100 { 101 len = n.len; 102 memset(a,0,sizeof(a)); 103 for(int i = 0 ; i < len ; i++) 104 a[i] = n.a[i]; 105 return *this; 106 } 107 istream& operator >> (istream & in, BigNum & b)//重载输入运算符 108 { 109 char ch[MAXSIZE * 4]; 110 in >> ch; 111 int l = strlen(ch); 112 ll count = 0, sum = 0; 113 for(int i = l - 1; i >= 0;) 114 { 115 sum = 0; 116 ll t = 1; 117 for(int j = 0; j < DLEN && i >= 0; j++, i--, t *= 10) 118 sum += (ch[i] - '0') * t; 119 b.a[count] = sum; 120 count++; 121 } 122 b.len = count++; 123 return in; 124 } 125 ostream& operator << (ostream& out, BigNum& b)//重载输出运算符 126 { 127 cout<<b.a[b.len - 1]; 128 for(int i = b.len - 2; i >= 0; i--) 129 { 130 cout.width(DLEN); 131 cout.fill('0'); 132 cout<<b.a[i]; 133 } 134 return out; 135 } 136 BigNum BigNum::operator + (const BigNum & T) const //重载加法 137 { 138 BigNum t(*this); 139 ll i,big;//位数 140 big = T.len > len ? T.len : len; 141 for(i = 0 ; i < big ; i++) 142 { 143 t.a[i] +=T.a[i]; 144 if(t.a[i] > MAXN) 145 { 146 t.a[i + 1]++; 147 t.a[i] -= MAXN + 1; 148 } 149 } 150 if(t.a[big] != 0) t.len = big + 1; 151 else t.len = big; 152 return t; 153 } 154 BigNum BigNum::operator - (const BigNum & T) const //重载减法 155 { 156 ll i,j,big; 157 bool flag; 158 BigNum t1,t2; 159 if(*this > T) 160 { 161 t1 = *this; 162 t2 = T; 163 flag = 0; 164 } 165 else 166 { 167 t1 = T; 168 t2 = *this; 169 flag = 1; 170 } 171 big = t1.len; 172 for(i = 0 ; i < big ; i++) 173 { 174 if(t1.a[i] < t2.a[i]) 175 { 176 j = i + 1; 177 while(t1.a[j] == 0) j++; 178 t1.a[j--]--; 179 while(j > i) t1.a[j--] += MAXN; 180 t1.a[i] += MAXN + 1 - t2.a[i]; 181 } 182 else t1.a[i] -= t2.a[i]; 183 } 184 t1.len = big; 185 while(t1.a[t1.len - 1] == 0 && t1.len > 1) 186 { 187 t1.len--; 188 big--; 189 } 190 if(flag)t1.a[big - 1] = 0 - t1.a[big - 1]; 191 return t1; 192 } 193 BigNum BigNum::operator * (const BigNum & T) const //重载乘法 194 { 195 BigNum ret; 196 ll i,j,up; 197 ll temp,temp1; 198 for(i = 0 ; i < len ; i++) 199 { 200 up = 0; 201 for(j = 0 ; j < T.len ; j++) 202 { 203 temp = a[i] * T.a[j] + ret.a[i + j] + up; 204 if(temp > MAXN) 205 { 206 temp1 = temp - temp / (MAXN + 1) * (MAXN + 1); 207 up = temp / (MAXN + 1); 208 ret.a[i + j] = temp1; 209 } 210 else 211 { 212 up = 0; 213 ret.a[i + j] = temp; 214 } 215 } 216 if(up != 0) 217 ret.a[i + j] = up; 218 } 219 ret.len = i + j; 220 while(ret.a[ret.len - 1] == 0 && ret.len > 1) ret.len--; 221 return ret; 222 } 223 BigNum BigNum::operator / (const ll & b) const //重载除法 224 { 225 BigNum ret; 226 ll i,down = 0; 227 for(i = len - 1 ; i >= 0 ; i--) 228 { 229 ret.a[i] = (a[i] + down * (MAXN + 1)) / b; 230 down = a[i] + down * (MAXN + 1) - ret.a[i] * b; 231 } 232 ret.len = len; 233 while(ret.a[ret.len - 1] == 0 && ret.len > 1) ret.len--; 234 return ret; 235 } 236 ll BigNum::operator % (const ll & b) const //重载取模 237 { 238 ll i,d=0; 239 for (i = len-1; i>=0; i--) 240 { 241 d = ((d * (MAXN+1))% b + a[i])% b; 242 } 243 return d; 244 } 245 BigNum BigNum::operator^(const ll & n) const //重载n次方 246 { 247 BigNum t,ret(1); 248 if(n < 0)exit(-1); 249 if(n == 0)return 1; 250 if(n == 1)return *this; 251 ll m = n; 252 while(m > 1) 253 { 254 t = *this; 255 ll i; 256 for(i = 1; i << 1 <= m; i <<= 1) 257 { 258 t = t * t; 259 } 260 m -= i; 261 ret = ret * t; 262 if(m == 1)ret = ret * (*this); 263 } 264 return ret; 265 } 266 bool BigNum::operator > (const BigNum & T) const //两大整数 大于号重载 267 { 268 ll ln; 269 if(len > T.len) return true; 270 else if(len == T.len) 271 { 272 ln = len - 1; 273 while(a[ln] == T.a[ln] && ln >= 0) ln--; 274 if(ln >= 0 && a[ln] > T.a[ln]) return true; 275 else return false; 276 } 277 else return false; 278 } 279 bool BigNum::operator > (const ll & t) const 280 { 281 return *this > BigNum(t); 282 } 283 bool BigNum::operator < (const BigNum & T) const //两大整数 小于号重载 284 { 285 return T > *this; 286 } 287 bool BigNum::operator < (const ll & t) const 288 { 289 return BigNum(t) > *this; 290 } 291 bool BigNum::operator == (const BigNum & T) const //两大整数 等于号重载 292 { 293 return !(T > *this) && !(*this > T); 294 } 295 bool BigNum::operator == (const ll & t) const 296 { 297 return BigNum(t) == *this; 298 } 299 void BigNum::print() 300 { 301 int i; 302 cout << a[len - 1]; 303 for(i = len - 2 ; i >= 0 ; i--) 304 { 305 cout.width(DLEN); 306 cout.fill('0'); 307 cout << a[i]; 308 } 309 } 310 311 int main() 312 { 313 int n; 314 cin >> n; 315 if(n == 1)puts("1"); 316 else if(n == 2)puts("5"); 317 else 318 { 319 BigNum a(1), b(5), c; 320 for(int i = 3; i <= n; i++) 321 { 322 c = BigNum(3LL) * b; 323 c = c - a; 324 c = c + BigNum(2LL); 325 a = b; 326 b = c; 327 } 328 cout<<c<<endl; 329 } 330 return 0; 331 }
越努力,越幸运