题目
2013 多校第二场 总结
题意:
有N个球,编号为0~n-1,一开始有A个箱子,编号0~A-1,将球x放到x%A那个箱子里。现在有B个新箱子,要把球x放到x%B那个箱子里,代价是|x%A-x%B|,求总代价。
题解:
N比较打所以不能暴力,可以这么想:
如果x`=x+LCM(A,B),那么|x%A-x%B|=|x`%A-x`%B|成立,且使得该等式成立的x和x`的最小差值也是LCM(A,B)。也就是在[0,LCM(A,B)]这个区间里,|x%A-x%B|遍历完所有可能的值。
连续的一段x中,当x%A和x%B没有发生跳变(从A-1变成0,B同理)时,|x%A-x%B|是相同的,即[0,LCM(A,B)]又可以分为一些小区间,每个小区间|x%A-x%B|是相同的。由于x%A只在x%A=A-1后跳变为0,所以总跳变数小于LCM(A,B)/A+LCM(A,B)/B,这样暴力找全部小区间是可以接受的,找到一个小区间后加上LCM(A,B)又是一个同样的区间。
//Time:109ms //Memory:352KB //Length:1065B #include <iostream> #include <cstdio> #include <cstdlib> #include <cstring> #include <cmath> #define MAXN 620 #define INF 10007 using namespace std; int gcd(int a,int b) { while(a%b!=0) a%=b,swap(a,b); return b; } int main() { //freopen("/home/moor/Code/input","r",stdin); int ncase,n,a,b; long long lca,l,la,lb,tt,ans,tmp,step; scanf("%d",&ncase); while(ncase--) { ans=0; scanf("%d%d%d",&n,&a,&b); lca=(long long)a*b/gcd(a,b); l=0,la=a,lb=b; for(;l<n;) { tt=min(min(la,lb),(long long)n); tmp=abs(l%a-l%b); step=(n-l+lca-1)/lca; if((n-l)%lca<tt-l&&(n-l)%lca!=0) ans+=((n-l)%lca)*step*tmp+(tt-l-(n-l)%lca)*(step-1)*tmp; else ans+=tmp*(tt-l)*step; l=tt; if(la==lb) break; if(l==la) la+=a; else lb+=b; } cout<<ans<<'\n'; } return 0; }