zoukankan      html  css  js  c++  java
  • hdu-4611-Balls Rearrangement

    题目链接:

    http://acm.hdu.edu.cn/showproblem.php?pid=4611

    题目大意:

    给一个n(n<=10^9),a,b.(a、b<10^6).求Σ|i%a-i%b|(0=<i<n).

    解题思路:

    被这题卡死了。开始想到用循环节来求,而当lcm(a,b)很大时没有效果,然后又想用余数和来求,有没发现什么有用的公式。。。

    然来可以一个区间一个区间的求,当lcm(a,b)较小时,直接暴力周期内的数即可。

    还是太弱了。。。

    代码:

    #include<iostream>
    #include<cmath>
    #include<cstdio>
    #include<cstdlib>
    #include<string>
    #include<cstring>
    #include<algorithm>
    #include<vector>
    #include<map>
    #include<set>
    #include<stack>
    #include<list>
    #include<queue>
    #define eps 1e-6
    #define INF 0x1f1f1f1f
    #define PI acos(-1.0)
    #define ll __int64
    #define lson l,m,(rt<<1)
    #define rson m+1,r,(rt<<1)|1
    //#pragma comment(linker, "/STACK:1024000000,1024000000")
    using namespace std;
    
    
    //freopen("data.in","r",stdin);
    //freopen("data.out","w",stdout);
    
    ll gcd(ll a,ll b)
    {
       if(a%b==0)
          return b;
       return gcd(b,a%b);
    }
    ll lcm(ll a,ll b)
    {
       return a/gcd(a,b)*b;
    }
    
    
    ll Cal(ll n,ll a,ll b) //计算<n的情况
    {
       ll res=0;
       for(ll i=0;i<n;i++)
       {
          res+=i%a>i%b?i%a-i%b:i%b-i%a;
       }
       return res;
    }
    
    int main()
    {
       ll t,a,b,n;
       ll M=10000000;
    
       //freopen("1001.in","r",stdin);
       //freopen("ans1001.out","w",stdout);
       scanf("%I64d",&t);
       while(t--)
       {
          scanf("%I64d%I64d%I64d",&n,&a,&b);
          ll temp=lcm(a,b),ans=0;
          if(temp<=M) //最小公倍数比较小
          {
             if(n<=temp) //直接暴力
             {
                printf("%I64d
    ",Cal(n,a,b));
                continue;
             } //按周期来算
             ll tt=Cal(temp,a,b);
             ans=ans+n/temp*tt;
             ans=ans+Cal(n%temp,a,b); //剩下的
             printf("%I64d
    ",ans);
          }
          else
          {
             ll p=0,q=0;
             ll num=0;
    
             while(num<=n) //个数
             {
                ll tt=p>q?p-q:q-p;//当前的差
                if(a-p<b-q) //第一个区间较短
                {
                   q=q+a-p; //填满,符号不变
                   num+=a-p; //个数
                   ans+=tt*(a-p);
                   if(num>=n) //个数超过了
                   {
                      ans-=(num-n)*tt; //减掉
                      break;
                   }
                   p=0;
                }
                else if(a-p>b-q)
                {
                   ans+=tt*(b-q);
                   p=p+b-q;
                   num+=b-q;
                   if(num>=n)
                   {
                      ans-=(num-n)*tt;
                      break;
                   }
                   q=0;
                }
                else
                {
                   ans+=tt*(a-p);
                   num+=a-p;
                   if(num>=n)
                   {
                      ans-=(num-n)*tt;
                      break;
                   }
                   p=q=0;
                }
                //printf("ans:%I64d p:%I64d q:%I64d num:%I64d
    ",ans,p,q,num);
                //system("pause");
             }
             printf("%I64d
    ",ans);
          }
       }
       return 0;
    }
    
    





  • 相关阅读:
    三层架构简单实例【转】
    排序 普通插入法排序
    排序 选择排序
    C#中的继承与覆盖
    排序 冒泡排序法
    c#使用Split分割字符串的几种方法
    GROUP BY,WHERE,HAVING之间的区别和用法
    递归 斐波那契数列
    【公众号系列】一文看懂税费改革
    【MM系列】SAP库龄报表逻辑理解
  • 原文地址:https://www.cnblogs.com/riskyer/p/3281366.html
Copyright © 2011-2022 走看看