一开始想到一个错误的组合数的解法。写了各种高精浪费两个小时才发现是错的。最后没办法只有爆搜出来找规律。
n=1 | 1 |
n=2 | 5 |
n=3 | 16 |
n=4 | 45 |
n=5 | 121 |
n=6 | 320 |
n=7 | 841 |
n=8 | 2205 |
n=9 | 5776 |
n=10 | 15125 |
最终推出来一个通项:a[n] = 3 * a[n-1] - a[n-2] + 2
再写个高精,问题就顺利解决了。
代码:
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn = 100 + 10;
const int maxm = 1000;
int f[maxn][maxm],temp[maxm];
int n;
void init()
{
freopen("bzoj1002.in","r",stdin);
freopen("bzoj1002.out","w",stdout);
}
void readdata()
{
scanf("%d",&n);
}
void mul(int *a,int m,int *b)
{
b[0] = a[0];
for(int i = 1;i <= a[0];i++)
{
b[i] = a[i] * m;
}
for(int i = 1;i <= b[0];i++)
{
b[i+1] += b[i] / 10;
b[i] %= 10;
}
int l = b[0] + 1;
while(b[l] > 0)
{
b[0]++;
b[l+1] += b[l] / 10;
b[l] %= 10;
l++;
}
while(b[0] > 1 && b[b[0]] == 0)--b[0];
}
void subs(int *a,int *b,int *c)
{
c[0] = a[0];
for(int i = 1;i <= c[0];i++)
{
if(a[i] < b[i])
{
a[i+1]--;
a[i] += 10;
}
c[i] = a[i] - b[i];
}
while(c[c[0]] == 0 && c[0] > 1)--c[0];
}
void add(int *a)
{
a[1] += 2;
for(int i = 1;i <= a[0];i++)
{
a[i+1] += a[i] / 10;
a[i] %= 10;
}
if(a[a[0]+1] > 0)++a[0];
}
void print(int *a)
{
for(int i = a[0];i >= 1;i--)
{
printf("%d",a[i]);
}
}
void solve()
{
if(n == 1)
{
printf("%d",1);
return;
}
if(n == 2)
{
printf("%d",5);
return;
}
f[1][0] = 1;f[1][1] = 1;
f[2][0] = 1;f[2][1] = 5;
for(int i = 3;i <= n;i++)
{
memset(temp,0,sizeof(temp));
mul(f[i-1],3,temp);
subs(temp,f[i-2],f[i]);
add(f[i]);
}
print(f[n]);
}
int main()
{
init();
readdata();
solve();
return 0;
}