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.如果说旧箱子和新箱子的大小是一样的话,那么我们就不用移动了。
2.如果说两个箱子都没有全用掉的话,即n<=a&&n<=b的话,那么我们也不用移动了。
如何进行优化呢,O(n)的复杂度已经超出了题目的要求。
令p为(a*b)/gcd(a,b),即a与b的最小公倍数,不知道大家有没有想到,无论对于哪个箱子而言,第0个位置放的永远都是编号为0,p,2*p…的球,它的位置是不变的,第1个位置放的永远都是编号为0+1,p+1,2*p+1…的球,它的位置改变了1…第i个位置放的永远都是编号为0+i,p+i,2*p+i…的球,它的位置改变了i,这样我们就能够在O(a,b的最小公倍数)内解决这个问题了,但是结果好像并没有那么理想,还是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;
}
对于当a与b的最小公倍数比较大的情况,我的时间复杂度为O(n),反之的话,就是O(a,b的最小公倍数),但是这样还是TLE,我们还是需要进一步找规律:
当我们把它展开时:
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…
不难发现:当a为0或者b为0的时候是我们的一个分界线,在相邻的两个0之间的差值是相等的,其实这不难理解,若某一个为0,那么它再往后一定是递增的,另一个数再往后的时候只要它没有遇到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);
//找到距离最近的一个零的长度
r+=abs(i%a-i%b)*c;
i+=c;
}
r*=n/p;
//循环出现,乘上循环次数即可
}
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了。