bzoj2190: [SDOI2008]仪仗队

复习一波反演。

非常粗暴的就是F(1)+2。

注意范围应该是n-1,因为在坐标系上,只有在原点看,点(1,2)才会挡住(2,4),最后加2就是上面和右边的两个点。

 

然而今天在caioj闲逛的时候发现了另外一种做法,就是用phi,抽象一下,设当前点为(x,y)那么应该xy互质才可以看到

(代码写得很丑,思路不是很清晰)

#include<cstdio>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
using namespace std;

int pr,prime[41000],u[41000];
bool v[41000];
void mobius_inversion()
{
    pr=0;u[1]=1;
    memset(v,true,sizeof(v));
    for(int i=2;i<=40000;i++)
    {
        if(v[i]==true)
        {
            prime[++pr]=i;
            u[i]=-1;
        }
        for(int j=1;j<=pr&&i*prime[j]<=40000;j++)
        {
            v[i*prime[j]]=false;
            if(i%prime[j]==0){u[i*prime[j]]=0;break;}
            u[i*prime[j]]=-u[i];
        }
        u[i]+=u[i-1];
    }
}
int getF(int n)
{
    int F=0,last;
    for(int d=1;d<=n;d=last+1)
    {
        last=n/(n/d);
        int G=(n/d)*(n/d);
        F+=(u[last]-u[d-1])*G;
    }
    return F;
}
int main()
{
    mobius_inversion();
    
    int n;
    scanf("%d",&n);
    printf("%d\n",getF(n-1)+2);
    
    return 0;
}

 

#include<cstdio>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
using namespace std;
int phi[41000],pr,prime[41000];
bool v[41000];
void getprime()
{
    pr=0;phi[1]=1;
    memset(v,false,sizeof(v));
    for(int i=2;i<=40000;i++)
    {
        if(v[i]==false)
        {
            prime[++pr]=i;
            phi[i]=i-1;
        }
        for(int j=1;j<=pr&&i*prime[j]<=40000;j++)
        {
            v[i*prime[j]]=true;
            if(i%prime[j]==0)
            {
                phi[i*prime[j]]=phi[i]*prime[j];
                break;
            }
            else phi[i*prime[j]]=phi[i]*(prime[j]-1);
        }
    }
}
int main()
{
    getprime();
    int n;
    scanf("%d",&n);n--;
    int ans=0;
    for(int i=1;i<=n;i++)ans+=phi[i];
    printf("%d\n",ans*2+1);
    return 0;
}

 

posted @ 2017-12-12 13:45  AKCqhzdy  阅读(174)  评论(0编辑  收藏  举报