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; }