http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=4056ios
有一個按鈕、一個燈、一個計時器和一個計數器,每按一次按鈕,計時器被置爲v+0.5,若當前燈是滅的,按一次後變亮,若當前燈是亮的,按一次後計數器+1,若當前時間nt%a=0,則按b次按鈕,若nt%c=0,則按d次按鈕,問最後時間爲t時,計數器的值c++
經過分析能夠發現,每lcm(a,c)個時間構成一個循環,因此只須要求出每一個lcm(a,c)的貢獻,做爲一段,再求出共有多少段便可,最後餘下部分不足一段再單獨處理,須要注意的是幾個邊界狀況,t=0時燈是滅的,因此第一段必定是以燈熄滅狀態爲起始條件,但後面的段可能以燈亮着狀態爲起始條件,這樣總體就會差1。
再分析會發現,對於每一段,咱們根本不用求出具體貢獻,只要先假設燈一直是亮的,求出所有貢獻,再求出燈熄滅了多少次就行,每熄滅一次counter數就要-1
能夠獲得這樣的公式:(t/a)*b+(t/c)*d+b+d-1 ,即表示從0~t時刻,假設燈一直是亮的,按鈕被按下的次數,由於實際t=0時燈是滅的,就至關於少按了一次按鈕
而後減去每一段燈熄滅的次數,再處理下結尾部分便可spa
#include <bits/stdc++.h> using namespace std; typedef long long LL; vector<long long>Q; long long a,b,c,d,v,t; long long pt,cntt; LL gcd(LL a,LL b){ //最大公約數if(b==0) return a; else return gcd(b,a%b); } LL lcm(LL a,LL b){ //最小公倍數return a/gcd(a,b)*b; //防止溢出 } void getblock(){ //獲得每一段的貢獻,即一段中燈熄滅次數 pt=lcm(a,c); cntt=0; Q.clear(); for(LL i=0;i<=pt;i+=a) Q.push_back(i); for(LL i=0;i<=pt;i+=c) Q.push_back(i); sort(Q.begin(),Q.end()); Q.erase(unique(Q.begin(),Q.end()),Q.end()); //去重 for(int i=1;i<Q.size();i++){ if(Q[i]-Q[i-1]>v) //先後差大於v,即表示燈熄滅 cntt++; } } int main(){ std::ios::sync_with_stdio(false); int cnt; cin>>cnt; while(cnt--){ cin>>a>>b>>c>>d>>v>>t; getblock(); long long ans=(t/a)*b+(t/c)*d+b+d-1; //從0~t按下的次數 long long blk=t/pt; //共有blk段 ans=ans- blk*cntt; //減去每段中燈熄滅的次數 long long last=t%pt; //最後不足一段時的邊界 for(LL i=1;Q[i]<=last;i++) //單獨處理最後不足一段部分 if(Q[i]-Q[i-1]>v) ans--; cout<<ans<<endl; } return 0; }