日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

HDU - 5459 Jesus Is Here(思维+非线性递推)

發布時間:2024/4/11 编程问答 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 HDU - 5459 Jesus Is Here(思维+非线性递推) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

題目鏈接:點擊查看

題意:字符串S僅由'c'和'f'組成,滿足S[i]=S[i-1]+S[i-2],求每兩個c之間的距離之

解析:題目不難懂,主要是這是一個非線性遞推,因為剛學會了暴力求解線性方程的系數,所以迫不及待的暴力求出了前10項的值,然后套用for循環來求系數,當然結果就是白白浪費了時間。

當然,既然字符串S滿足斐波那契數列的規律,那么我們也可以從這里入手,大膽假設結果與前兩項有關系。

網上的大多數方法我都沒看懂。。主要是寫的太抽象了,我想不過來(還是太笨了)

這里說一下兩個方法,一個是昨天上課的時候一個大佬同學講的,還有一個是從網上看到的比較好的方法,廢話不多說,直接切入正題:

方法一:利用平均值

首先我們需要四個輔助數組,分別是len,num,dis和sum,分別代表:字符串長度、字符串中'c'的個數、每一個'c'到達字符串左端的距離和、結果。

根據字面意思,很容易就能推出len和num的公式,都是斐波那契數列:

len[i]=len[i-1]+len[i-2];

num[i]=num[i-1]+num[i-2];

然后是dis,可以知道,S[i]字符串是由S[i-2]與S[i-1]拼合而成,所以原來S[i-2]中的'c'點到左端的距離不變,仍為dis[i-2],而S[i-1]中的num[i-1]個'c'點到左端的距離均多了len[i-2]的長度,故可以推出:

dis[i]=dis[i-2]+dis[i-1]+len[i-2]*num[i-1];

最后就是利用平均值求一下sum的關系了,首先,易知S[i]=S[i-1]+S[i-2]+?,那么關鍵就是對?的求解。

其中,?代表的是S[i-2]與S[i-1]交叉部分的距離和。

我們先將S[i]分解為S[i-2]和S[i-1]兩個部分,以下簡稱為左端與右端,那么每一個左端的點右端的點的距離和,可以轉換為左端的點的平均值到右端的點的平均值的距離,然后乘以左端的點右端的點的數量的乘積,表示由這么多條路線可行,想一想是不是?

sum[i]=sum[i-1]+sum[i-2]+(dis[i-1]/num[i-1]-dis[i-2]/num[i-2]+len[i-2])*num[i-1]*num[i-2];

這里還需要優化一下,因為公式中帶著除法,會丟失精度,所以我們將公式展開,可以得到最終的形式:

sum[i]=sum[i-1]+sum[i-2]+dis[i-1]*num[i-2]-dis[i-2]*num[i-1]+len[i-2]*num[i-1]*num[i-2];

注意:當處理減號時,記得加mod再減去mod,防止負數取模出現異常錯誤。

上代碼:

#include<iostream> #include<cstdio> #include<string> #include<cstring> #include<algorithm> #include<stack> #include<queue> #include<map> #include<sstream> using namespace std;typedef long long LL;const int inf=0x3f3f3f3f;const int N=202314;const int mod=530600414;LL len[N],num[N],sum[N],dis[N];//len:長度,num:c的個數,sum:結果,dis:所有c到左端的距離和void init() {len[1]=1;len[2]=2;num[1]=1;num[2]=0;for(int i=3;i<N;i++){len[i]=(len[i-1]+len[i-2])%mod;num[i]=(num[i-1]+num[i-2])%mod;}sum[1]=0;sum[2]=0;dis[1]=0;dis[2]=0;sum[3]=0;sum[4]=0;sum[5]=5;for(int i=3;i<N;i++){dis[i]=((dis[i-1]+dis[i-2])%mod+(len[i-2]*num[i-1])%mod)%mod;}for(int i=6;i<N;i++){sum[i]=(sum[i-1]+sum[i-2]+((dis[i-1]*num[i-2])%mod-(dis[i-2]*num[i-1])%mod+mod)%mod+((len[i-2]*num[i-1])%mod*num[i-2])%mod)%mod;} }int main() { // freopen("input.txt","r",stdin);int w;init();cin>>w;int kase=0;while(w--){int n;scanf("%d",&n);printf("Case #%d: %lld\n",++kase,sum[n]);}return 0; }

方法二:利用中點

這個方法需要借助五個輔助數組,分別是:len,num,dis,dis2和sum,其余四個與上述方法的意義相同,而dis2代表的與dis恰好相反,即每一個'c'到達字符串左端的距離和

這個方法比較好理解,仍然是將S[i]分為左右兩個部分,然后左端的點到右端的距離和乘右端的點的數量,加上右端的點到左端的距離和乘左端的點的數量,就是?所表示的了。光看文字描述可能有些抽象,轉換成公式再看一遍可能就好很多了:

sum[i]=sum[i-1]+sum[i-2]+dis2[i-2]*num[i-1]+dis[i-1]*num[i-2];

這個方法的好處就是不用擔心會出現負數,從而取模異常的情況。

有個小細節需要處理:就是關于dis和dis2數組,如果dis是從0開始計數,則dis2需要從1開始計數,反之亦然,因為防止重復計數。好了,上代碼:

#include<iostream> #include<cstdio> #include<string> #include<cstring> #include<algorithm> #include<stack> #include<queue> #include<map> #include<sstream> using namespace std;typedef long long LL;const int inf=0x3f3f3f3f;const int N=202314;const int mod=530600414;LL len[N],num[N],sum[N],dis[N],dis2[N];//len:長度,num:c的個數,sum:結果,dis:所有c到左端的距離和,dis2:所有c到右端的距離和 void init() {len[1]=1;len[2]=2;num[1]=1;num[2]=0;for(int i=3;i<N;i++){len[i]=(len[i-1]+len[i-2])%mod;num[i]=(num[i-1]+num[i-2])%mod;}sum[1]=0;sum[2]=0;dis[1]=0;dis[2]=0;dis2[1]=1;dis2[2]=0; sum[3]=0;sum[4]=0;sum[5]=5;for(int i=3;i<N;i++){dis[i]=((dis[i-1]+dis[i-2])%mod+(len[i-2]*num[i-1])%mod)%mod;dis2[i]=((dis2[i-1]+dis2[i-2])%mod+(len[i-1]*num[i-2])%mod)%mod;}for(int i=6;i<N;i++){sum[i]=((sum[i-1]+sum[i-2])%mod+(dis[i-1]*num[i-2])%mod+(dis2[i-2]*num[i-1])%mod)%mod;} }int main() { // freopen("input.txt","r",stdin);int w;init();cin>>w;int kase=0;while(w--){int n;scanf("%d",&n);printf("Case #%d: %lld\n",++kase,sum[n]);}return 0; }

?

總結

以上是生活随笔為你收集整理的HDU - 5459 Jesus Is Here(思维+非线性递推)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。