Description
众所周知,HYF有很多小姊妹。 HYF每天放学之后都要跟(不同的)MM约会。HYF这天约会的时候不巧被jzt撞上了……虽然换一个新的MM约会这种事情对于HYF来说如同家常便饭,所谓“好事不出门,坏事传千里”,jzt迅速将这个消息传播开来。 每个听到这个消息的人首先会震惊一段时间(他怎么又换MM了- -~!),但是这样的震惊只会持续2个时刻(因为这对于HYF来说太正常了= =~!)。如果他在第i个时刻听到这个消息,就会从第(i+2)个时刻开始传播这个消息,每个时刻把这个消息告诉两个人,当然他只会告诉不知道这个消息的人。但是当他连续告诉了10个人之后,他就会口干舌燥,停止传播。 jzt在第0时刻撞到HYF(当然jzt也有震惊时间),请问第N时刻共有多少人知道了这个消息?
Input Format
一行一个整数N,表示第N时刻。
Output Format
一行一个整数,表示N分钟后知道这个消息的总人数。
Sample Input
【输入样例1】
4
【输入样例2】
1
【输入样例3】
10
Sample Output
【输出样例1】
11
【输出样例2】
1
【输出样例3】
651
Hint
【样例1解释】
时刻0:一开始只有jzt知道
时刻2:jzt开始传播,时刻2传播给A和B,时刻3传播给C和D,时刻4传播给E和F;
时刻4:A和B在4开始传播,时刻4传播给2×2=4个人,传播给H、I、J、K;
最后知道消息的共有:jzt,A,B,C,D,E,F,H,I,J,K,共11个人。
【数据规模】
20%的数据,N<=20
60%的数据,N<=1000
100%的数据,N<=10000
【题解】
一题比较简单的递推,设f[i]记录第i时刻才知道这件事的人f[0]=1,f[i]=f[i-2]+f[i-3]+f[i-4]+f[i-5]+f[i-6];(最后做个累加就行了)
由于f最后算出来结果很大所以用高精度(刚开始怕会爆内存和超时所以就压4位,事实证明不压位也是能过的)(旁边有的大神高精度时数组开大了就超时最后验证只能开800然而开了7000的我一脸懵逼)
由于数据范围比较大,最好用一个滚动数组七个一循环(事实证明不滚动也不会炸)
由于是递推 还可以用矩阵乘法快速幂的算法优化(虽然矩阵算起来会比较慢 但加上快速幂使算法整体降成log n级别的)
矩阵:
a [1,0,0,0,0,0,0,1]
*f [1,0,2,2,2,2,2,0]
[0,0,2,2,2,2,2,0]
[0,0,1,0,0,0,0,0]
[0,0,0,1,0,0,0,0]
[0,0,0,0,1,0,0,0]
[0,0,0,0,0,1,0,0]
[0,0,0,0,0,0,1,0]
[0,0,0,0,0,0,0,1]
#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <stack>
#include <vector>
#include <queue>
#include <map>
using namespace std;
int i,j,k,l,m,n;
struct info
{
int tot,a[7000];
}f[10],sum,ans;
info operator *(info A,int b)
{
info c;int i,j;
// memset(c.a,0,sizeof c.a);
for (i=1,j=A.tot;i<=j;i++) c.a[i]=A.a[i]*b;c.a[j+1]=c.a[j+2]=0;
for (i=1;i<=j;i++) c.a[i+1]+=c.a[i]/10000,c.a[i]%=10000;
for (;c.a[j+1]!=0;j++,c.a[j+1]=c.a[j]/10000,c.a[j]%=10000);c.tot=j;
return c;
}
info operator +(info A,info B)
{
info c;int i,j;
// memset(c.a,0,sizeof c.a);
for (i=1,j=max(A.tot,B.tot);i<=j;i++) c.a[i]=A.a[i]+B.a[i];c.a[j+1]=0;
for (i=1;i<=j;i++) c.a[i+1]+=c.a[i]/10000,c.a[i]%=10000;
for (;c.a[j+1]!=0;j++,c.a[j+1]=c.a[j]/10000,c.a[j]%=10000);c.tot=j;
return c;
}
info operator -(info A,info B)
{
info c;int i,j;
c=A;
for (i=1,j=min(A.tot,B.tot);i<=j;i++) c.a[i]=c.a[i]-B.a[i];
for (i=1,j=max(A.tot,B.tot);i<=j;i++)
if (c.a[i]<0) c.a[i]+=10000,c.a[i+1]-=1;
for (;c.a[j]==0;j--);c.tot=j;
return c;
}
int main()
{
scanf("%d",&n);
m=1;
f[0].tot=1;f[0].a[1]=1;sum.tot=1;sum.a[1]=0;ans.tot=1;ans.a[1]=1;
for (i=1;i<=n;i++)
{
f[m]=sum*2;
ans=ans+f[m];
if (m==0) k=6;else k=m-1;
sum=sum+f[k];
m=m+1;if (m==7) m=0;
sum=sum-f[m];
}
printf("%d",ans.a[ans.tot]);
for (i=ans.tot-1;i;i--) printf("%d",ans.a[i]);
if (ans.a[i]>999) printf("%d",ans.a[i]);
else if (ans.a[i]>99) printf("0%d",ans.a[i]);
else if (ans.a[i]>9) printf("00%d",ans.a[i]);
else printf("000%d",ans.a[i]);
}