bzoj 2401: 陶陶的难题I 数论

2401: 陶陶的难题I

Time Limit: 10 Sec  Memory Limit: 128 MB
Submit: 89  Solved: 24
[Submit][Status]

Description

最近陶陶在研究数论,某天他偶然遇到一道题:对于给定的正整数???,求出
下面这样一个式子的值:

其中LCM(a???, b???)表示正整数???和???最小公倍数,即能同时被a???和b???整除的最小正
整数。
作为神犇的陶陶,当然轻松秒杀了这道题。不过他希望你写一个程序,用来
检验他算的答案是否正确。

Input

第一行包含一个正整数???T,表示有T???组测试数据。接下来???T<=10^5
行,每行给出一个正整数N,N<=10^6。

Output

包含T???行,依次给出对应的答案。

Sample Input

7
1
10
100
1000
10000
100000
1000000

Sample Output

1
2127
18446224
183011304660
1827127167830060
18269345553999897648
182690854273058293758232

   最开始试图通过一种很逗逼的做法弄这道题,其实也A的程序复杂度完全相同,都是一个调和计数的O(nlogn),但是由于我最开始的方法for语句内高精度加要多算那么一两次,所以就稳稳地被卡常数了,而且这个常数致使我删掉了300+的高精度模板,改用一个pair表示int128。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<string>
using namespace std;
#define MAXN 1000001
typedef long long qword;
int prime[MAXN+10],topp=-1;
bool pflag[MAXN+10];
int phi[MAXN+10];
qword maxval=100000000000000000LL;
struct mypair
{
        qword first,second;
        mypair(qword x,qword y):first(x),second(y){};
        mypair(){};
        inline void operator += (mypair& pp)
        {
                first+=pp.first;
                second+=pp.second;
                if (second>=maxval)
                {
                        first++;
                        second-=maxval;
                }
        }
        inline void operator -=(mypair& pp)
        {
                first-=pp.first;
                second-=pp.second;
                if (second<0)
                {
                        second+=maxval;
                        first--;
                }
        }
};
mypair res[MAXN+10];
void init()
{
        register int i,j;
        phi[1]=1;
        for (i=2;i<MAXN;i++)
        {
                if (!pflag[i])
                {
                        prime[++topp]=i;
                        phi[i]=i-1;
                }
                for (j=0;j<=topp && i*prime[j]<MAXN;j++)
                {
                        pflag[i*prime[j]]=true;
                        if (i%prime[j]==0)
                        {
                                phi[i*prime[j]]=phi[i]*prime[j];
                                break;
                        }
                        phi[i*prime[j]]=phi[i]*(prime[j]-1);
                }
        }
        register mypair g,gt,g0;
        g.first=g.second=0;;
        for (i=1;i<MAXN;i++)res[i].first=0,res[i].second=0;
        for (i=1;i<MAXN;i++)
        {
                g.first+=(qword)i*i*phi[i]/maxval;
                g.second+=(qword)i*i*phi[i]%maxval;
                if (g.second>=maxval)
                {
                        g.first+=g.second/maxval;
                        g.second%=maxval;
                }
                gt.first=gt.second=0;g0=g;
                for (j=1;i*j<MAXN;j++)
                {
                        gt+=g0;
                        res[i*j]+=gt;
                        if (i*j+j<MAXN)
                        {
                                res[(i+1)*j]-=gt;
                        }
                }
        }
        //for (i=1;i<MAXN;i++)res[i].first-=100000;
        for (i=2;i<MAXN;i++)
                res[i]+=res[i-1];
}
int main()
{
        //freopen("input.txt","r",stdin);
        //freopen("b.txt","w",stdout);
        init();
        qword i,j,k,x,y,z,n,m;
        qword nn;
        scanf("%lld",&nn);
        qword ans=0;
        while (nn--)
        {
                scanf("%lld",&n);
                if (res[n].first)
                        printf("%lld%017lld\n",res[n].first,res[n].second);
                else
                        printf("%lld\n",res[n].second);
        }
}

TLE

  换了一种方法,联想lcmsum的做法,通过与n互质数的和为n*phi[n]/2这个公式可以很轻松推出正解,但是还是非常慢,至少还是可以A掉吧。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<string>
using namespace std;
#define MAXN 1000001
typedef unsigned long long qword;
int prime[MAXN+10],topp=-1;
bool pflag[MAXN+10];
int phi[MAXN+10];
qword maxval=100000000000000000LLU;
struct mypair
{
        qword first,second;
        mypair(qword x,qword y):first(x),second(y){};
        mypair(){};
        inline void operator += (mypair& pp)
        {
                first+=pp.first;
                second+=pp.second;
                if (second>=maxval)
                {
                        first++;
                        second-=maxval;
                }
        }
        inline void operator -=(mypair& pp)
        {
                first-=pp.first;
                second-=pp.second;
                if (second<0)
                {
                        second+=maxval;
                        first--;
                }
        }
};
mypair res[MAXN+10];
void init()
{
        register int i,j;
        phi[1]=1;
        for (i=2;i<MAXN;i++)
        {
                if (!pflag[i])
                {
                        prime[++topp]=i;
                        phi[i]=i-1;
                }
                for (j=0;j<=topp && i*prime[j]<MAXN;j++)
                {
                        pflag[i*prime[j]]=true;
                        if (i%prime[j]==0)
                        {
                                phi[i*prime[j]]=phi[i]*prime[j];
                                break;
                        }
                        phi[i*prime[j]]=phi[i]*(prime[j]-1);
                }
        }
        for (i=1;i<MAXN;i++)
        {
                register qword x=(qword)phi[i]*i/2;
                if (i==1)x=1;
                for (j=i;j<MAXN;j+=i)
                {
                        res[j].second+=x*j;
                        if (res[j].second>=maxval)
                        {
                                res[j].first+=res[j].second/maxval;
                                res[j].second%=maxval;
                        }
                }
        }
        for (i=1;i<MAXN;i++)
        {
                res[i].first*=2,res[i].second*=2;
                res[i].second-=i;
                if (res[i].second>=maxval)
                {
                        res[i].second-=maxval;
                        res[i].first++;
                }
                if (res[i].second<0)
                {
                        res[i].second+=maxval;
                        res[i].first--;
                }
                res[i]+=res[i-1];
        }
        return ;
        /*
        register mypair g,gt,g0;
        g.first=g.second=0;;
        for (i=1;i<MAXN;i++)res[i].first=0,res[i].second=0;
        for (i=1;i<MAXN;i++)
        {
                g.second+=(qword)i*i*phi[i];
                if (g.second>=maxval)
                {
                        g.first+=g.second/maxval;
                        g.second%=maxval;
                }
                gt.first=gt.second=0;g0=g;
                for (j=1;i*j<MAXN;j++)
                {
                        gt+=g0;
                        res[i*j]+=gt;
                        if (i*j+j<MAXN)
                        {
                                res[(i+1)*j]-=gt;
                        }
                }
        }
        for (i=2;i<MAXN;i++)
                res[i]+=res[i-1];*/
}
int main()
{
        //freopen("input.txt","r",stdin);
        //freopen("b.txt","w",stdout);
        init();
        qword i,j,k,x,y,z,n,m;
        qword nn;
        scanf("%lld",&nn);
        qword ans=0;
        while (nn--)
        {
                scanf("%lld",&n);
                if (res[n].first)
                        printf("%llu%017llu\n",res[n].first,res[n].second);
                else
                        printf("%llu\n",res[n].second);
        }
}
时间: 2024-10-27 13:01:43

bzoj 2401: 陶陶的难题I 数论的相关文章

bzoj 2402: 陶陶的难题II 二分答案维护凸包

2402: 陶陶的难题II Time Limit: 40 Sec  Memory Limit: 128 MBSec  Special JudgeSubmit: 68  Solved: 45[Submit][Status] Description Input 第一行包含一个正整数N,表示树中结点的个数. 第二行包含N个正实数,第i个数表示xi (1<=xi<=10^5). 第三行包含N个正实数,第i个数表示yi (1<=yi<=10^5). 第四行包含N个正实数,第i个数表示pi (

[BZOJ2402]陶陶的难题II(树链剖分+线段树维护凸包+分数规划)

陶陶的难题II 时间限制:40s      空间限制:128MB 题目描述 输入格式 第一行包含一个正整数N,表示树中结点的个数. 第二行包含N个正实数,第i个数表示xi (1<=xi<=10^5). 第三行包含N个正实数,第i个数表示yi (1<=yi<=10^5). 第四行包含N个正实数,第i个数表示pi (1<=pi<=10^5). 第五行包含N个正实数,第i个数表示qi (1<=qi<=10^5). 下面有N-1行,每行包含两个正整数a,b(1<

陶陶摘苹果(升级版)

题目描述 又是一年秋季时,陶陶家的苹果树结了n个果子.陶陶又跑去摘苹果,这次她有一个a公分的椅子.当他手够不着时,他会站到椅子上再试试. 这次与NOIp2005普及组第一题不同的是:陶陶之前搬凳子,力气只剩下s了.当然,每次摘苹果时都要用一定的力气.陶陶想知道在s<0之前最多能摘到多少个苹果. 现在已知n个苹果到达地上的高度xi,椅子的高度a,陶陶手伸直的最大长度b,陶陶所剩的力气s,陶陶摘一个苹果需要的力气yi,求陶陶最多能摘到多少个苹果. 输入输出格式 输入格式: 第1行:两个数 苹果数n,

NOIP2005-普及组复赛-第一题-陶陶摘苹果

题目描述 Description 陶陶家的院子里有一棵苹果树,每到秋天树上就会结出10个苹果.苹果成熟的时候,陶陶就会跑去摘苹果.陶陶有个30厘米高的板凳,当她不能直接用手摘到苹果的时候,就会踩到板凳上再试试. 现在已知10个苹果到地面的高度,以及陶陶把手伸直的时候能够达到的最大高度,请帮陶陶算一下她能够摘到的苹果的数目.假设她碰到苹果,苹果就会掉下来. 输入输出格式 Input/output 输入格式:输入文件apple.in包括两行数据.第一行包含10个100到200之间(包括100和200

P1478 陶陶摘苹果(升级版)

题目描述 又是一年秋季时,陶陶家的苹果树结了n个果子.陶陶又跑去摘苹果,这次她有一个a公分的椅子.当他手够不着时,他会站到椅子上再试试. 这次与NOIp2005普及组第一题不同的是:陶陶之前搬凳子,力气只剩下s了.当然,每次摘苹果时都要用一定的力气.陶陶想知道在s<0之前最多能摘到多少个苹果. 现在已知n个苹果到达地上的高度xi,椅子的高度a,陶陶手伸直的最大长度b,陶陶所剩的力气s,陶陶摘一个苹果需要的力气yi,求陶陶最多能摘到多少个苹果. 输入输出格式 输入格式: 第1行:两个数 苹果数n,

Codevs 5564 陶陶摘苹果2

5564 陶陶摘苹果2 时间限制: 1 s 空间限制: 16000 KB 题目等级 : 白银 Silver 题目描述 Description 陶陶已经够高摘到所有苹果了,但是他力量有限,最大承受质量为Q kg,有K个苹果,每个苹果有自己的价值和质量,请你帮陶陶看看怎么摘能够价值最大. 输入描述 Input Description 两个整数Q,K,代表最大承受,苹果的数量. 以下k行,两个整数w,v,代表每个苹果的质量和价值. 输出描述 Output Description 输出一个整数代表最大的

洛谷-陶陶摘苹果-数组

题目描述 Description 陶陶家的院子里有一棵苹果树,每到秋天树上就会结出10个苹果.苹果成熟的时候,陶陶就会跑去摘苹果.陶陶有个30厘米高的板凳,当她不能直接用手摘到苹果的时候,就会踩到板凳上再试试. 现在已知10个苹果到地面的高度,以及陶陶把手伸直的时候能够达到的最大高度,请帮陶陶算一下她能够摘到的苹果的数目.假设她碰到苹果,苹果就会掉下来. 输入输出格式 Input/output 输入格式:输入文件apple.in包括两行数据.第一行包含10个100到200之间(包括100和200

洛谷-陶陶摘苹果(升级版)-数组

题目描述 Description 又是一年秋季时,陶陶家的苹果树结了n个果子.陶陶又跑去摘苹果,这次她有一个a公分的椅子.当他手够不着时,他会站到椅子上再试试. 这次与NOIp2005普及组第一题不同的是:陶陶之前搬凳子,力气只剩下s了.当然,每次摘苹果时都要用一定的力气.陶陶想知道在s<0之前最多能摘到多少个苹果.    现在已知n个苹果到达地上的高度xi,椅子的高度a,陶陶手伸直的最大长度b,陶陶所剩的力气s,陶陶摘一个苹果需要的力气yi,求陶陶最多能摘到多少个苹果. 输入输出格式 Inpu

武汉科技大学ACM:1007: 陶陶摘苹果

Problem Description 陶陶家的院子里有一棵苹果树,每到秋天树上就会结出10个苹果.苹果成熟的时候,陶陶就会跑去摘苹果.陶陶有个30厘米高的板凳,当她不能直接用手摘到苹果的时候,就会踩到板凳上再试试. 现在已知10个苹果到地面的高度,以及陶陶把手伸直的时候能够达到的最大高度,请帮陶陶算一下她能够摘到的苹果的数目.假设她碰到苹果,苹果就会掉下来. Input 输入包括两行数据.第一行包含10个100到200之间(包括100和200)的整数(以厘米为单位)分别表示10个苹果到地面的高