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 
  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<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<endl;
329     }
330     return 0;
331 }

 

转载于:https://www.cnblogs.com/fzl194/p/9678566.html

你可能感兴趣的:(BZOJ 1002 轮状病毒 矩阵树定理)