hdoj4710 规律题
2018-3-1
題目大意比較容易理解,一開始覺得很簡單,附上TLE的代碼:
#include<iostream> using namespace std;int t,n,a,b;int main(){cin>>t;while (t--){cin>>n>>a>>b;if (a==b){cout<<0<<endl;continue;}int r=0;for (int i=0;i<n;i++){int t=i%a-i%b;if (t>0) r+=t;else r+=-t;}cout<<r<<endl;}return 0; }直接輸出為零的情況:
1.如果說舊箱子和新箱子的大小是一樣的話,那么我們就不用移動(dòng)了。
2.如果說兩個(gè)箱子都沒有全用掉的話,即n<=a&&n<=b的話,那么我們也不用移動(dòng)了。
如何進(jìn)行優(yōu)化呢,O(n)的復(fù)雜度已經(jīng)超出了題目的要求。
令p為(a*b)/gcd(a,b),即a與b的最小公倍數(shù),不知道大家有沒有想到,無論對于哪個(gè)箱子而言,第0個(gè)位置放的永遠(yuǎn)都是編號為0,p,2*p…的球,它的位置是不變的,第1個(gè)位置放的永遠(yuǎn)都是編號為0+1,p+1,2*p+1…的球,它的位置改變了1…第i個(gè)位置放的永遠(yuǎn)都是編號為0+i,p+i,2*p+i…的球,它的位置改變了i,這樣我們就能夠在O(a,b的最小公倍數(shù))內(nèi)解決這個(gè)問題了,但是結(jié)果好像并沒有那么理想,還是TLE:
#include<iostream> #include<cmath> using namespace std;typedef long long ll; const int N = 100000; ll t,n,a,b;ll gcd(ll a,ll b){while(b^=a^=b^=a%=b);return a;} int main(){cin>>t;while (t--){cin>>n>>a>>b;if (a==b||(a>=n&&b>=n)){cout<<0<<endl;continue;}ll p=(a*b)/gcd(a,b);ll r=0,m=min(n,p),t=n%p,c=(n/p+1);for (int i=0;i<t;i++){r+=abs(i%a-i%b)*c;}c=c-1;for (int i=t;i<m;i++){r+=abs(i%a-i%b)*c;}// int p=(a*b)/gcd(a,b);// int r=0,m=min(n,p);// for (int i=0;i<m;i++){// int k=n/p;// if (i<=n%p) k+=1;// r+=abs(i%a-i%b)*k;// }cout<<r<<endl;}return 0; }對于當(dāng)a與b的最小公倍數(shù)比較大的情況,我的時(shí)間復(fù)雜度為O(n),反之的話,就是O(a,b的最小公倍數(shù)),但是這樣還是TLE,我們還是需要進(jìn)一步找規(guī)律:
當(dāng)我們把它展開時(shí):
a:0,1,2,3,4,0,1,2,3,4,0,1,2,3,4…
b:0,1,2,0,1,2,0,1,2,0,1,2,0,1,2…
c:0,0,0,3,3,2,1,1,1,4,1,1,2,2,2…
不難發(fā)現(xiàn):當(dāng)a為0或者b為0的時(shí)候是我們的一個(gè)分界線,在相鄰的兩個(gè)0之間的差值是相等的,其實(shí)這不難理解,若某一個(gè)為0,那么它再往后一定是遞增的,另一個(gè)數(shù)再往后的時(shí)候只要它沒有遇到0,那么它也是遞增的…
#include<iostream> #include<cmath> using namespace std;typedef long long ll; const int N = 100000; ll t,n,a,b;ll gcd(ll a,ll b){while(b^=a^=b^=a%=b);return a;} ll min_(ll a,ll b){if (a<b) return a;return b; }int main(){cin>>t;while (t--){cin>>n>>a>>b;if (a==b||(a>=n&&b>=n)){cout<<0<<endl;continue;}ll p=(a*b)/gcd(a,b),r=0;if (n>p){for (int i=0;i<p;){int c=min_(a-i%a,b-i%b);//找到距離最近的一個(gè)零的長度r+=abs(i%a-i%b)*c;i+=c;}r*=n/p; //循環(huán)出現(xiàn),乘上循環(huán)次數(shù)即可}int q=n%p;for (int i=0;i<q;){int c=min_(min_(a-i%a,b-i%b),q-i);r+=abs(i%a-i%b)*c;i+=c;}cout<<r<<endl;}return 0; }在TLE了那么多次之后終于AC了。
總結(jié)
以上是生活随笔為你收集整理的hdoj4710 规律题的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: SDWebImage源码阅读(三)UII
- 下一篇: window下安装nvm、node.js