【消息傳播】

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]);
  }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章