FJOI2007 轮状病毒

HYSBZ_1002

    努力了一大节毛邓课,终于把这个题的递推公式写出来了O(∩_∩)O~

    由于推倒过程有点不好叙述,所以在此就只列出结论了,如果有什么疑问或者建议可以一起讨论哈。

    设f[n]表示第n个原子和中心相连的病毒数,g[n]表示第n个原子不和中心相连的病毒数,那么最后的结果就是f[n]+g[n]。同时还需要一个辅助的表达式h[n],表示将环变成一条直链(首尾没有直接相连的线)后的病毒数(用h[n]去推其他表达式的时候可以看作是第n个原子和第1个原子不连线,而在计算h[n]的时候实际上也可以看成是第n-1个原子和第n个原子之间不连线,这样更容易得到h[n]=f[n-1]+2*h[n-1]-h[n-2]

    那么有:

    f[n]= 2*f[n-1]+h[n-1]-h[n-2]

    g[n]=f[n-1]+g[n-1]+h[n-1]

    h[n]=f[n-1]+2*h[n-1]-h[n-2]

#include<stdio.h>
#include<string.h>
#define MAXD 110
int N;
struct BigInteger
{
char a[MAXD];
const static int D = 100;
void init(int n)
{
int i;
for(i = 0; i < D; i ++)
{
a[i] = n % 10;
n /= 10;
}
}
BigInteger add(BigInteger &b)
{
int i, s, c;
BigInteger ans;
c = 0;
for(i = 0; i < D; i ++)
{
s = a[i] + b.a[i] + c;
ans.a[i] = s % 10;
c = s / 10;
}
return ans;
}
BigInteger minus(BigInteger &b)
{
int i, s, c;
BigInteger ans;
c = 0;
for(i = 0; i < D; i ++)
{
s = a[i] + c;
if(s >= b.a[i])
{
ans.a[i] = s - b.a[i];
c = 0;
}
else
{
c = -1;
ans.a[i] = s + 10 - b.a[i];
}
}
return ans;
}
void print()
{
int i;
for(i = D - 1; i > 0 && a[i] == 0; i --);
for(; i >= 0; i --)
printf("%d", a[i]);
}
}f[MAXD], h[MAXD], g[MAXD];
void init()
{
f[1].init(0), g[1].init(1), h[1].init(1);
f[2].init(3), g[2].init(2), h[2].init(3);
}
void solve()
{
int i;
for(i = 3; i <= N; i ++)
{
f[i] = f[i - 1].add(f[i - 1]).add(h[i - 1]).minus(h[i - 2]);
g[i] = f[i - 1].add(g[i - 1]).add(h[i - 1]);
h[i] = f[i - 1].add(h[i - 1]).add(h[i - 1]).minus(h[i - 2]);
}
f[N].add(g[N]).print();
printf("\n");
}
int main()
{
while(scanf("%d", &N) == 1)
{
init();
solve();
}
return 0;
}

 

你可能感兴趣的:(2007)