[HDOJ]1005. Number Sequence
數字游戲,如果硬說它有算法的話,那也只能說去找規律了。
初看本題的人,會覺得這這是一個簡單的遞歸題目,其實我一開始也是這么想的,但后來提交了如下代碼后我才明白。
using?namespace?std;
int?main()
{
????int?a,b,n;
????while(cin>>a>>b>>n?&&?n)
????{
????????int?f1?=?1,f2?=?1,f,t?=?3;
????????while(t?<=?n)
????????{
????????????f?=?(a*f2?+?b*f1)%7;
????????????f1?=?f2;
????????????f2?=?f;
????????????++t;
????????}
????????cout<<f<<endl;
????}
????return?0;
}
??????細細看下題目中的條件要求:1 <= n <= 100,000,000,你就應該明白本題絕不是簡單的遞歸就可以解決的,上述代碼的答案是TLE.(后來加):其實看到題目中出現求余運算,我就應該很快的反應過來,這道題目絕對不是簡單的遞歸運算就可以解決問題的,因為求余運算會有一定的重復,所以,本題中的數據一定會出現重復,從重復中找到規律,問題就可以解決了。
??????其實解決本題的方法是找出規律,當f1,f2和a b的值確定后,你就可以利用題目中給出的公式往后計算了,如果我們把所有fn的取值算作一個隊列(非數據結構中的隊列)的話,可以肯定的是,這個隊列不會延展太長,到了一定長度,肯定會出現重復,而我們需要做的就是找出這個重復點。
??????什么時候會出現重復呢,如果我們假定隊列是如下循環的:
f1?=?f2;
f2?=?f;
那么很簡單就可以推出:當f1 = 1,且f2 = 1時就會出現隊列一開始的循環了。此時我們就不需要繼續向下遞歸了。不過我們需要把出現循環以前的所有值都保存下來。相比于時間復雜度來說,這點空間復雜度還是值得的。
這樣寫了代碼,結果卻Memory Limit Exceeded,郁悶,今天太晚了,明天再搞。
#include?<vector>
using?namespace?std;
int?main()
{
????int?a,b,n;
????while(cin>>a>>b>>n?&&?n)
????{
????????vector<int>?ivec;
????????int?f1?=?1,f2?=?1,f,t?=?3,count,num;
????????ivec.push_back(f1);
????????ivec.push_back(f2);
????????while(1)
????????{
????????????f?=?(a*f2?+?b*f1)%7;
????????????f1?=?f2;
????????????f2?=?f;
????????????if(f1?==?1?&&?f2?==?1)
????????????????break;
????????????else
????????????????ivec.push_back(f);
????????????++t;
????????}
????????count?=?t?-?2;
????????num?=?n%count;
????????if(num?==?0)
????????????num?=?count;
????????cout<<ivec.at(num?-?1)<<endl;
????????ivec.clear();
????}
????return?0;
}
??????昨天晚上找了杭電的WSN大牛問了下,一開始他也不是很清楚,只是讓我把vector<int> ivec;設置為全局變量試下,這個我早已經試過,結果還是Memory limit Exceeded,問題應該不是出在這里,我初步猜測應該是有一組測試數據,讓vector<int> ivec一直在執行push_back()操作,所以才會出現上述錯誤,看了WSN的AC代碼后,他與我想法的區別在于數字的重復不一定是我所想的從頭開始的重復,也可能是在中間部分開始重復的,舉個簡單的例子,這里沒有理由依據:1 1 2 5 6 5 4 4 8 6 2 5 4....,如果是這樣下去的話,從5 和 4開始就是重復了,并不是從開始的1 和1 開始重復的,這樣也有道理。而且也實際上應該這么考慮才對。
??????后來,我隨便試了幾組數據,就發現出現了問題,當我輸入21 56 45這組數據時,上面的程度沒有輸出,Debug后才知道,其實不是沒有輸出,而是程序在while(1)處進入了死循環,這樣就導致我的ivec一直不間斷的進行push_back()操作,才會有了開始的Memory Limit Exceeded這種錯誤。既然找到了錯誤,下面就剩下修改代碼了,我決定采用WSN的想法,在判斷是否開始重復時多加入一個條件判斷,修改后AC,代碼及注釋如下:
?
#include?<iostream>#include?<vector>
using?namespace?std;
vector<int>?ivec;
//布爾數組元素flag[i][j]如果為true,則說明前面已經出現了i?和?j兩者的組合
bool?flag[7][7];
void?init(void)
{
????int?i,j;
????for(i?=?0;i?<?7;++i)
????????for(j?=?0;j<?7;++j)
????????????flag[i][j]?=?false;
}
int?main()
{
????int?a,b,n;
????while(cin>>a>>b>>n)
????{
????????if(a?==?0&&b?==?0&&n?==?0)
????????????break;
????????ivec.clear();
????????init();
????????ivec.push_back(1);
????????ivec.push_back(1);
????????flag[1][1]?=?true;
????????int?count?=?1,f;
????????while(1)
????????{
????????????f?=?(a*ivec.at(count)%7?+?b*ivec.at(count?-?1)%7)%7;
????????????ivec.push_back(f);
????????????++count;
????????????//如果flag變量為true,則說明前面已經出現了這兩者的組合,出現重復,無需下一步計算,直接break退出即可
????????????if(flag[ivec.at(count)][ivec.at(count?-?1)]?==?true)
????????????????break;
????????????else
????????????????flag[ivec.at(count)][ivec.at(count?-?1)]?=?true;
????????}
????????//count中存放的是ivec中出現循環前的元素總個數,注意ivec中的下標是從0開始計數的
????????count?=?count?-?1;
????????if(n?<?count)
????????????cout<<ivec.at(n-1)<<endl;
????????else
????????{
????????????int?j;
????????????//for循環的目的是找出從那個地方開始重復,此處應該是從j處開始循環,注意j是從0下標開始計數的
????????????for(j?=?0;;++j)
????????????????if(ivec.at(count)?==?ivec.at(j)?&&?ivec.at(count?+?1)?==?ivec.at(j+1))
????????????????????break;
????????????n?=?(n?-?j)%(count?-?j);
????????????if(n?==?0)
????????????????n?=?count?-?j;
????????????n?+=?j;
????????????cout<<ivec.at(n-1)<<endl;
????????}
????}
????return?0;
}
后記:在我解決我這道題出現問題的過程中,我也在網上搜索了很多,找到了一些代碼去測試,結果發現其實杭電服務器上關于本題的測試數據是不完整的,就拿我剛才那個測試數據來說:21 56? n來說,其循環應該為:
1 1 0 0 0 0 0 0 0 ...........,而我在網上找到的一些代碼,比如下面這個代碼:(來源:http://hi.baidu.com/chenghui2050/blog/item/84c552ad3124ee0f4a36d660.html)
using?namespace?std;
int?main()
{
????int?a,b,i;
????long?long?f[55],n;
????while(cin>>a>>b>>n)
????{
????????if(a==0&&b==0&&n==0)break;
????????f[1]=f[2]=1;
????????for(i=3;i<=49;i++)
????????f[i]=(a*f[i-1]+b*f[i-2])%7;
????????cout<<f[n%48]<<endl;
????}
????return?0;
}如果輸入21 56 49時,正確輸出應該是0,而上述代碼卻是1,明顯是錯誤的,但卻莫名的AC,希望看到的朋友們注意下。題目中并沒有明確說明不會出現0 0這種情況,要注意。
按照WSN的思路考慮的話,應該是考慮比較全面的了,贊the lord of WSNs,呵呵.
這個問題先告一段落了,殘酷的測試數據,倒。。。
轉載于:https://www.cnblogs.com/krisdy/archive/2009/04/12/1434013.html
總結
以上是生活随笔為你收集整理的[HDOJ]1005. Number Sequence的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Every Woman is beaut
- 下一篇: RSA的加解密过程--(转自CSDN,学