ACM训练周末总结—10月29日

来源:互联网 发布:星际战甲腐蚀投射数据 编辑:程序博客网 时间:2024/05/29 09:16

        这个半周开始做数学专题的题了,直到现在还有两道题就是没调通QAQ。

        W题是个大水题,假设有两个数a,b,给出gcd(a,b),lcm(a,b),求a,b(a要求最小的)。a*b=gcd(a,b)*lcm(a,b),而a最小就是gcd,所以只要gcd%lcm=0,就输出gcd,lcm就可以。

        A题,给出一个数n,找出x,y,z,x^2+y^2=z^2且x,y,z<=n,x,y,z两两之间互素。找出满足条件的组数和n以内没被使用过数的个数。这个题就需要膜拜大佬了,也是这道题给了我许多启发,学习寻找题目突破点。下面是一位大佬的推导过程。http://blog.csdn.net/corncsd/article/details/16879899

http://www.cnblogs.com/zpfbuaa/p/5049407.html另一个证明

首先,因为x,y,z互素,所以x,y不可能都是偶数(偶数平方还是偶数,偶数偶数还是偶数)。假设x,y,都是奇数,x=2a+1,y=2b+1,x^2是奇数,y^2是奇数,则z^2是偶数,z是偶数。因为偶数的平方一定能被4整除,但是z^2=x^2+y^2=4(a² + b² + a + b) + 2 不能被4整除,所以x,y不可能都是奇数。于是x,y只能是一奇一偶,z只能是奇数,设x为奇数,y为偶数。则z+x和z-x都是偶数。设z+x=2*u,z-x=2*v。
  z=u+v
  x=u-v

因为z和x互素,所以u和v也一定互素(假设u和v不互素,u=w*k1,v=w*k2,z=w*(k1+k2),x=w*(k1-k2),z和x不互素,矛盾)。把z和x代入x^2+y^2=z^2得,y^2=4*u*v,也就是(y/2)^2=u*v。由于u和v互素,乘积又是一个平方数,所以u和v都是一个平方数(因为(u,v)=1,u=u*(u,v)=(u^2,uv)=(u^2,(y/2)^2)=(u,y/2)^2,u是平方数,同理v也是平方数)。
  设u=a^2,v=b^2,a,b互素并且是一奇一偶(若a,b不互素,则u,v不互素,矛盾。由于u,v互素,则至少其中一个是奇数,又因为y是偶数,所以u*v是偶数,所以u,v一奇一偶,奇数的平方是奇数,偶数的平方是偶数,所以a,b也一奇一偶)。
       最后就有 z=a^2+b^2,x=a^2-b^2,y=2*a*b (a,b互素,一奇一偶,a>b)。(对于任意勾股数组都有此原理)

       从这个题感到浓浓的数学味道,从有限的条件入手,分类讨论,导出公式,完成代码。我还是太嫩了,下次一定独立推出公式。

      V题是给出n,k,求n^k的前三位和后三位,后三位简单,就是快速幂取模就行,至于前三位n^k=10^(klog10(n)),算出浮点数log10(k)*n,舍弃小数点前的数(只影响位数10的几次方),然后pow算出剩下的10^x,在乘100就对了。

      X题是给出n,找出1到n数中两两之间最大公因数的和。原问题只需要求出来f(n)=gcd(1,n)+gcd(2,n)+…+gcd(n-1,n)再求和。由于gcd(i,n)一定是n的约数,只需要枚举约数x然后考虑有多少不超过n的数i  满足gcd(i,n)=x。这等价于gcd(i/x,n/x)等于1,也就是phi(n/x)。

 在这里再附上欧拉函数模版:

        void phi_table()
{
    for(int i=2;i<=4000010;i++) phi[i] = 0;
    phi[1]=1;
    for(int i=2;i<=4000010;i++)
    {
        if(!phi[i])
        {
            for(int j=i;j<=4000010;j+=i)
            {
                if(!phi[j]) phi[j]=j;
                phi[j]=phi[j]/i*(i-1);
            }
        }
    }
}

快速幂取模(其实保存过了)

//计算a*b % m,将b按二进制分解
LL FaMulti(LL a, LL b)
{
    LL res = 0;
    while(b)
    {
        if(b & 1)
        {
            res += a;
            res %= m;
        }
        a += a;
        a %= m;
        b >>= 1;
    }
    return res;
}
// 计算a^b % m,将b按二进制分解
LL FaPow(LL a, LL b)
{
    LL res = 1;
    while(b)
    {
        if(b & 1)
        {
            res = FaMulti(res, a);
        }
        a = FaMulti(a, a);
        b >>= 1;
    }
    return res;
}

大数加减乘除去取模

string div(string a,int b)//除
{
    string c;
    int len=a.length();
    int ans=0;
    char s;
    for(int i=0;i<len;i++)
    {
        ans=ans*10+a[i]-'0';
        s=ans/b+'0';
        ans%=b;
        c+=s;
    }
    int pos=0;
    while(pos<len && c[pos]=='0') pos++;
    if(pos==len) return "0";
    return c.substr(pos);
}
int mod(string s,int x)//取模
{
    int len=s.length();
    int ans=0;
    for(int i=0;i<len;i++)
    {
        ans=(ans*10+s[i]-'0')%x;
    }
    return ans;
}
string mul(string a,int b)//乘
{
    string c;
    char s;
    int len=a.length();
    int ok=0;
    for(int i=len-1;i>=0;i--)
    {
        int temp=(a[i]-'0')*b+ok;
        ok=temp/10;
        s=temp%10+'0';
        c=s+c;
    }
    while(ok)
    {
        s=ok%10+'0';
        c=s+c;
        ok/=10;
    }
    return c;
}
string add(string a,string b)//加
{
    string c;
    int len1=a.length();
    int len2=b.length();
    int len=max(len1,len2);
    for(int i=len1;i<len;i++)
        a="0"+a;
    for(int i=len2;i<len;i++)
        b="0"+b;
    int ok=0;
    for(int i=len-1;i>=0;i--)
    {
        char temp=a[i]+b[i]-'0'+ok;
        if(temp>'9')
        {
            ok=1;
            temp-=10;
        }
        else ok=0;
        c=temp+c;
    }
    if(ok) c="1"+c;
    return c;
}

原创粉丝点击