回 帖 发 新 帖 刷新版面

主题:第63次编程比赛我的代码和测试数据

第一题就是求给定n,在小于n的数中,有多少个互质数对。基本上可以递推得到,val[n+1]=val[n]+phi(n),phi的功能就是得到小于n的且与n互质的数的个数。generate_primes()生成这样的一个数列comp,其中comp[i]为数i的最小质因子,比如comp[4]=2,comp[5]=5,comp[9]=3....。
具体讲一下phi的原理:计算小于n的且与n互质的数的个数,采取了排除的方法。我们知道对于任何一个数都可以表示成n=a1*a1....a2*a2...an*an..也就是若干的质数的积,且1<a1<a2<a3...<an。那我们要做的就是排除掉小于等于n的数中有因子a1,a2,...an的数的个数就行了。现在我们希望快速知道对于任意一个数他的a1是多少,这就是comp[]的作用。如果知道了a1那么就可以得到小于等于n的且与n有公共因子的数的个数为n/a1,那么与n互质的就有res=(n-n/a1)个。接下来对于函有a2因子的数有n/a2个,但要加上n/(a1*a2)个,因为对于他们的公倍数显然排除了两次,这样与n互质的就有res-n/a2+n/(a1*a2)=res-(n-n/a1)/a2=res-res/a2。对于a3则是res=res-res/a3。于是有如下的关系
1  res=n
2  res=res-res/ai
直到处理完所有的ai
[code=c]
#include <cstdio>



#define MAXPRIME 1000001 
int comp[MAXPRIME];

void generate_primes() { //生成1-1000000的最小质因子
    int i;
    comp[0] = comp[1] = 1;
    for (i=2; i<MAXPRIME; i+=2)
        comp[i] = 2;
    for (i=3; i<=(MAXPRIME-1)/i; i+=2) {
        if (!comp[i]) {
                        comp[i] = i;
            for (int j=i*i; j<MAXPRIME; j+=i+i)
                comp[j] = i;
        }
    }
        for (; i < MAXPRIME; i += 2)
                if (!comp[i])
                        comp[i] = i;
}

int phi(int n) {  //得到小于n的且与n互质的个数
        int res = n;//n的作用仅仅为了取得不同的因子
        while (n > 1)
        {
                int f = comp[n];
                res /= f;//=>等同于(res-res/f)
                res *= f-1;//
                while (n % f == 0)//去掉已经处理了的因子,也就是把相同的ai都除掉
                        n /= f;
        }
    return res;
}

long long val[MAXPRIME];

int main()
{
        generate_primes();
        for (int i = 2; i < MAXPRIME; i++)//递推
                val[i] = val[i-1] + phi(i);

        int kases;
        for (scanf("%d", &kases); kases; kases--)
        {
                int x;
                scanf("%d", &x);
                printf("%I64ld\n", 2*val[x] + 1);
        }
        return 0;
}
[/code]

第二题比较简单,就是排序以及判断。先对鬼和捉鬼大师进行y的降序排序,如果y相同就按x的降序排序。然后基本按照如下代码片段进行判断。完全讲清楚,需要画图,挺麻烦,大家不明白的可以提出。
[code=c]
for (int i=0; i<n; ++i) {
                // 找到捉鬼大师的坐标使得 x <= g[i].x && y >= g[i].y
                while(j <m && b[j].y >= g[i].y) {
                        minx= min(minx,b[j].x);
                        ++j;
                }
                if (minx<= g[i].x) continue;
                printf("%d %d\n",g[i].x,g[i].y);
        }
[/code]

回复列表 (共2个回复)

沙发

这个比赛很有意思   支持这个比赛   支持plane

板凳

第63次阿,我刚来的时候才举办到十几次。

最近一直被自己的项目中如何解除循环引用的问题所困扰,没时间思考其它的问题了。

我来回复

您尚未登录,请登录后再回复。点此登录或注册