zoukankan      html  css  js  c++  java
  • hdu 2973 YAPTCHA(C++)(威尔逊定理)

    hdu 2973 YAPTCHA

    点击做题网站链接

    题目描述

    Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)

    Problem Description
    The math department has been having problems lately. Due to immense amount of unsolicited automated programs which were crawling across their pages, they decided to put Yet-Another-Public-Turing-Test-to-Tell-Computers-and-Humans-Apart on their webpages. In short, to get access to their scientific papers, one have to prove yourself eligible and worthy, i.e. solve a mathematic riddle.
    However, the test turned out difficult for some math PhD students and even for some professors. Therefore, the math department wants to write a helper program which solves this task (it is not irrational, as they are going to make money on selling the program).
    The task that is presented to anyone visiting the start page of the math department is as follows: given a natural n, compute
    在这里插入图片描述
    where [x] denotes the largest integer not greater than x.

    Input
    The first line contains the number of queries t(t<=106)t (t <= 10^6). Each query consist of one natural number n(1<=n<=106)n (1 <= n <= 10^6).

    Output
    For each n given in the input output the value of Sn.

    Sample Input
    13
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    100
    1000
    10000

    Sample Output
    0
    1
    1
    2
    2
    2
    2
    3
    3
    4
    28
    207
    1609

    中文翻译

    Problem Description
           spacespacespacespacespacespacespace数学系最近遇到了问题。由于大量未经请求的自动程序在他们的网页上爬行,他们决定在他们的网页上放置Yet-Another-Public-Turing-Test-to-Tell-Computers-and-Humans-Apart(一次公开的图灵测试,以便在他们的网页上区分计算机和人类)。简而言之,要获得他们的科学论文,必须证明自己有资格和有价值,即解决下面一个数学之谜。
           spacespacespacespacespacespacespace然而,对于一些数学博士生甚至一些教授来说,这项测试都很困难。因此,数学系想要编写一个帮助程序来解决这个任务(这不是不合理的,因为他们会在出售程序时赚钱)。
           spacespacespacespacespacespacespace呈现给访问数学部门起始页面的任何人的任务如下:给定一个自然的n,计算
    在这里插入图片描述
           spacespacespacespacespacespacespace其中[x]表示不大于x的最大整数。(即取整)

    Input
           spacespacespacespacespacespacespace 第一行包含查询数 tt<=106t(t <= 10 ^ 6)。每个查询由一个自然数n组成1<=n<=106(1 <= n <= 10 ^ 6)

    Output
           spacespacespacespacespacespacespace 对于输入中给出的每个n,输出Sn的值。

    Sample Input
    13
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    100
    1000
    10000

    Sample Output
    0
    1
    1
    2
    2
    2
    2
    3
    3
    4
    28
    207
    1609

    解题思路

    题目的意思很简单,就是输入一个n,你按照公式运算输出一个Sn。

    先贴出威尔逊定理:当且仅当p为素数时,( p -1 )! ≡ -1 ( mod p )。即:若p为质数,则p能被(p-1)!+1整除。

    根据这道题的样子:Sn=k=1n[(3k+6)!+13k+7[(3k+6)!3k+7]]S_n=sum_{k=1}^n[frac{(3k+6)!+1}{3k+7}-[frac{(3k+6)!}{3k+7}]]

    很容易就可以联想到威尔逊定理,令p=3k+7,得原式Sn=k=1n[(p1)!+1p[(p1)!p]]S_n=sum_{k=1}^n[frac{(p-1)!+1}{p}-[frac{(p-1)!}{p}]],再讨论p是不是素数即可:

    1. 当p是素数时,(p1)!+1pfrac{(p-1)!+1}{p}是整数,而(p1)!pfrac{(p-1)!}{p}不是整数。又题目把(p1)!pfrac{(p-1)!}{p}取整,所以(p1)!+1p[(p1)!p]frac{(p-1)!+1}{p}-[frac{(p-1)!}{p}]为1,再把(p1)!+1p[(p1)!p]frac{(p-1)!+1}{p}-[frac{(p-1)!}{p}]取整还是1。所以在题目的和式中该部分为1;

    2. 当p是合数时,(p1)!+1pfrac{(p-1)!+1}{p}不是整数,且(p1)!pfrac{(p-1)!}{p}也不是整数。把(p1)!pfrac{(p-1)!}{p}取整,所以(p1)!+1p[(p1)!p]frac{(p-1)!+1}{p}-[frac{(p-1)!}{p}]为不到1的小数,再把(p1)!+1p[(p1)!p]frac{(p-1)!+1}{p}-[frac{(p-1)!}{p}]取整得到0。所以在题目的和式中该部分为0;

    综上,令p=3k+7,(k=1,2,3,…,n),若p为素数,和式为1;若p为合数,和式为0。对k=1~n求和。

    所以筛一遍素数,在筛的过程中,找出形如3k+7的素数即可。

    筛素数用线筛快,而且上限是3k+7,又k<=n,且n&lt;=106n&lt;=10^6,所以要筛的范围是223×106+73 imes10^6+7。用数组valid[i]记录i是否为素数,用数组a[k]记录对应的3k+7=i的k每一和式项是否为1还是0,用s[n]保存结果。

    问题解答

    #include <iostream>
    #include <string.h>
    using namespace std;
    
    const int MAXN = 1e6+1;//开a[n]和s[n]的数组大小
    const int MAX = 3*(MAXN-1)+7+1;//开判断是否为素数数组的范围
    int prime[MAX];//记录哪些数字是素数,即prime[MAX]是一个素数集合
    bool valid[MAX];
        //数组valid[i]记录i是否为素数。初始所有的valid[i]为true。
        //线性筛选完之后valid[i]=ture的就是素数。
    void LinearPrime()
    {
    	int tot = 0;
    
    	memset(valid,true,sizeof(valid));//初始所有的valid[i]为true
    	for(int i=2;i<=MAX;++i)//对于2到n中的每一个i
    	{
    		if( valid[i] )//如果i是素数
    		{
    			prime[tot] = i;//那么就将i这个素数加入素数集合ans[MAX]中
    			tot++;
    		}
    		for(int j=0;j<tot;++j)//对于当前素数集合中每一个元素ans[j]
    		{
    			if( i*prime[j]>MAX ) break;//若i*prime[j]>n,结束循环
    			//(因为确定素数的倍数超过讨论范围,没必要进行下一步了)
    			valid[i*prime[j]] = false;//将确定素数的倍数记录为合数
    			if( i%prime[j]==0 ) break;//保证每个合数只会被它的最小质因数筛去
    		}
    	}
    }
    
    int a[MAXN];//a[i],如果i是素数就为1,不是就为0(初始化全为0)
    int s[MAXN];//求和函数,初始化全为0,正好s[1]=0
    
    int main()
    {
        int t,n;
        cin >> t;
        LinearPrime();
        for(int k=1;k<=MAXN;++k)
        {
            if(valid[3*k+7]==1)//如果3*k+7是素数
                a[k] = 1;//那么对应的a[k]就为1
        }
    
        for(int i=2;i<MAXN;++i)
    		s[i] = s[i-1]+a[i];//s[i]的递推公式
    	while(t--)
    	{
    	    cin >> n;
    	    cout << s[n] << endl;
    	}
    }
    
  • 相关阅读:
    MySQL系列(二)
    MySQL系列(一)
    RabbitMQ的安装部署
    RabbitMQ原理介绍
    消息中间件metaq
    消息中间件之zookper安装部署
    ZooKeeper基本原理
    消息中间件剖析
    了解Node.js
    windows下使用Git
  • 原文地址:https://www.cnblogs.com/yuzilan/p/10626068.html
Copyright © 2011-2022 走看看