http://acm.hdu.edu.cn/showproblem.php?pid=4611
从A中向B中移动和从B中向A中移动的效果是一样的,我们假设从B中向A中移动 而且A>B
我们先求出所有在B[0]上的点移动到A上的分布情况 可以求出花费
当我们要求B[1]上的点移动到A上的分布情况时 相当于B[0]在A上的分布情况水平右移一个单位
由于B[1]点对于B[0]也向后移动了一个单位 所有相对位置没有移动
但是A中有一个地方需要改动 那就是每次A中最后一个位置的点需要移动到A[0]位置(因为对A进行取模的原因)
还有一个要注意的情况就是 B 在向后移动的时候 点的个数可能会减小 要特殊处理一下
代码:
#include<iostream> #include<cstdio> #include<string> #include<cstring> #include<cmath> #include<set> #include<map> #include<stack> #include<vector> #include<algorithm> #include<queue> #include<bitset> #include<deque> #include<numeric> //#pragma comment(linker, "/STACK:1024000000,1024000000") using namespace std; typedef long long ll; typedef unsigned int uint; typedef pair<int,int> pp; const double eps=1e-9; const int INF=0x3f3f3f3f; const ll MOD=1000000007; const int H=210000; const int K=100001; ll a[H]; int f(int x) { return x+K; } ll readya(ll N,ll A,ll B) { ll lcm=A*B/(__gcd(A,B)); int n=lcm/B; int k=0; ll num=(N/B); if(N%B) ++num; for(int i=0;i<n;++i) { a[f(k)]+=num/n; k=(k+B)%A; } ll M=num%n; k=0; while(M--) { a[f(k)]++; k=(k+B)%A; } ll tmp=0; for(int i=1;i<A;++i) tmp+=a[f(i)]*i; return tmp; } int main() { //freopen("data.in","r",stdin); int T; scanf("%d",&T); while(T--) { memset(a,0,sizeof(a)); ll N,A,B; cin>>N>>A>>B; if(B>A) swap(A,B); if(A==B) {printf("0 ");continue;} ll L=0; ll R=readya(N,A,B); int num=N/B; if(N%B) ++num; ll ans=L+R; for(int i=1;i<B;++i) { a[f(-i)]=a[f(A-i)]; R-=(a[f(A-i)]*(A-i)); L+=(a[f(-i)]*i); a[f(A-i)]=0; int tmp=(N-i)/B; if((N-i)%B) ++tmp; if(tmp!=num) { int x=tmp*B+i; a[f(x%A-i)]--; if(x%A-i>0) {R-=abs(x%A-i);} if(x%A-i<0) {L-=abs(x%A-i);} num=tmp; } ans+=(L+R); } cout<<ans<<endl; } return 0; }