【消息传播】

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]);
  }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值