2022年数学专项练习2(模运算与快速幂)-POJ

28 篇文章 0 订阅
13 篇文章 0 订阅

2022年数学专项练习2(模运算与快速幂)-POJ

A - The Last Non-zero Digit

题目

In this problem you will be given two decimal integer number N, M. You will have to find the last non-zero digit of the NPM.This means no of permutations of N things taking M at a time.

Input

The input contains several lines of input. Each line of the input file contains two integers N (0 <= N<= 20000000), M (0 <= M <= N).

Output

For each line of the input you should output a single digit, which is the last non-zero digit of NPM. For example, if NPM is 720 then the last non-zero digit is 2. So in this case your output should be 2.

Sample

InputcopyOutputcopy
10 10 10 5 25 68 4 2

解析

原文链接:
POJ 1150 ——The Last Non-zero Digit(数论)

这个题怎么来做呢?先别急,我们先来讨论一下下面几个子问题:
1.如何求出n阶乘中质因数x(比如说5)出现的次数?
比如说15的阶乘 :123456789101112131415
由于5这个质因数只在5的倍数里面才出现,所以我从5,10,15中各抽出一个5,这相当于有15/5个质因数5,之后5,10,15就变成了1,2,3;
由于非5的倍数显然不在考虑范围之内,所以我们只需继续讨论它的子问题3!即可。
这样,我们可以用递归来解决这个问题。有了这个方法,我们是不是能够轻易地解决n!末尾有多少个0呢?想想看…n!后0的个数是不是就和某个质因数的个数有关呢?_
比如说,我们要求5出现的次数,可以这样写:

int get5(int n)//计算n!中质因子5的出现次数
{
    if(n==0)
        return 0;
    return n/5+get5(n/5);
}

2.如何求出n!阶乘最后非0位?
比如说我们要找10!最后非0位,由于质因数2和5组合之后会使得末尾产生0.那么我们不妨把10!中2,5质因数全部去掉,(但是请注意2的数目其实比5的要多,所以我们要在最后考虑多余的2对末位的影响)
如 12345678910 去掉2 ,5 因子后 就是1131137191,由于2,5因子已经被去除,那么剩下的数字末尾一定是3,7,9,1中四者之一。然后我们再求出这么一串数相乘以后末尾的数是几.最后再补上2对末位的影响即可!

总结一下,求10!最后一个非0位的步骤如下:
step1:首先将10!中所有2,5因子去掉;
step2:然后求出剩下的一串数字相乘后末尾的那个数。
step3:由于去掉的2比5多,最后还要考虑多余的那部分2对结果的影响。
step4:输出答案!

这里面步骤2是个难点。如何求出剩下的这串数字相乘后最后一位是几呢?这可以转化成求出这些数里面末尾是3,7,9的数字出现的次数(为啥?因为这些数的n次方是有规律的,周期为4,不信你可以推一下)

好,现在问题就是如何求出这串数字中末尾3,7,9各自出现的次数了;

一个数列实际上可以分成偶数列和奇数列,以123456789*10为例

分成1 3 5 7 9, 2 4 6 8 10

这样我们尝试分别进行统计,可以发现,实际上2,4,6,8,10中的个数也就是1 2 3 4 5中的个数,也就是说我们又把这个问题划分成了一个原来问题的子问题。

f(n) = f(n/2) + g(n),g(n)表示奇数列中的数目,所以我们需要解决g(n)

再次观察g(n)

实际上又分成了两部分1 3 7 9 11 13 17 19 21。。。以及5的奇倍数5,15,25。。。说明又出现了子问题,如果要统计这个数列中末尾为x(1,3,7,9)的个数可以这样写:g(n,x) = n/10+(n%10 >= x)+g(n/5,x)

这样利用了两个递归方程,我们就可以在lgn的时间内计算出末尾为1,3,7,9的数的个数了

好了,现在我们得到了这串数字中末尾是3,7,9的数字的个数,我们利用循环节的性质可以快速地算出这串数字相乘后mod 10的结果,在考虑下当时多除的2(其实也可以用循环节来处理),便可求出答案!

解决了上面两个子问题,我想求P(n,m)最后一个非0位就变得十分容易了。

P(n,m)实际上等于 n! / (n-m)!

我们可以求出n! 和(n-m)!中质因数2,5,3,7,9分别出现的次数,然后再各自相减。

然后再用循环节处理,即可!

BTW,这里还要注意一个trick,就是2的出现次数如果小于5,(这对于排列数来说是可能的)我们可以直接输出5,如果2的数目等于5,那么2的循环节不需要考虑。至于3,7,9的循环节,由于这些数的4次方末位刚好是1,所以就不需要特殊考虑了。

#include<iostream>
#include<cstring>
#include<cmath>
using namespace std;

int get2(int n)//计算n!中质因子2的出现次数
{
    if(n==0)
        return 0;
    return n/2+get2(n/2);
}

int get5(int n)//计算n!中质因子5的出现次数
{
    if(n==0)
        return 0;
    return n/5+get5(n/5);
}

//
int g(int n,int x)//计算f(1) to f(n) 中,奇数数列中末尾为x的数出现的次数
{
    if(n==0)
        return 0;
    return n/10+(n%10>=x)+g(n/5,x);
}

int getx(int n,int x)//计算f(1) to f(n)中,末尾为x的数的出现次数
{
    if(n==0)
        return 0;
    return getx(n/2,x)+g(n,x);
}
//

int table[4][4] =
{
        6,2,4,8,//2^n%10的循环节,注意如果2的个数为0时候,结果应该是1,要特殊处理。 
        1,3,9,7,//3
        1,7,9,3,//7
        1,9,1,9,//9    
};//3,7,9的循环节中第一位,刚好是1,故不需要考虑这些数字出现次数为0的情况。


int main()
{

    int n,m;
    int num2;
    int num3;
    int num5;
    int num7;
    int num9;
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        num2=get2(n)-get2(n-m);
        num5=get5(n)-get5(n-m);
        num3=getx(n,3)-getx(n-m,3);
        num7=getx(n,7)-getx(n-m,7);
        num9=getx(n,9)-getx(n-m,9);
        int res=1;
        if(num5>num2)
        {
            printf("5\n");
            continue;
        }
        else 
        {
            if(num2!=num5)
            {
                res*=table[0][(num2-num5)%4];
                res%=10;
            }//如果num2==num5,那么2^0次方mod 10应该为1 ,而不是table中的6,所以要特殊处理。
            
            res*=table[1][num3%4];
            res%=10;
            res*=table[2][num7%4];
            res%=10;
            res*=table[3][num9%4];
            res%=10;
        }
        printf("%d\n",res);
    }
    return 0;
}

B - An Easy Problem!

题目

Have you heard the fact “The base of every normal number system is 10” ? Of course, I am not talking about number systems like Stern Brockot Number System. This problem has nothing to do with this fact but may have some similarity.

You will be given an N based integer number R and you are given the guaranty that R is divisible by (N-1). You will have to print the smallest possible value for N. The range for N is 2 <= N <= 62 and the digit symbols for 62 based number is (0…9 and A…Z and a…z). Similarly, the digit symbols for 61 based number system is (0…9 and A…Z and a…y) and so on.

Input

Each line in the input will contain an integer (as defined in mathematics) number of any integer base (2…62). You will have to determine what is the smallest possible base of that number for the given conditions. No invalid number will be given as input. The largest size of the input file will be 32KB.

Output

If number with such condition is not possible output the line “such number is impossible!” For each line of input there will be only a single line of output. The output will always be in decimal number system.

Sample

InputcopyOutputcopy
3 5 A4 6 11

解析

题意:输入一个数问这个数是在2-64进制中 哪个进制下的最大值。

算法思路:(来源discuss讨论区)

设输入的是abcd,假设其解是n进制,则有
(annn + bnn + cn + d)%(n-1)=0
则有:( (annn)%(n-1)+ (bnn)%(n-1)+ (cn)%(n-1)+ d )%(n-1)=0
则有:( (a* (n%(n-1)) (n%(n-1)) (n%(n-1)))+ (b (n%(n-1)) (n%(n-1)))+(c (n%(n-1) +d ) %(n-1)=0
则有: (a
111+b11+c*1+d)%(n-1)=0
则有:(a+b+c+d)%(n-1)=0

注意:

If number with such condition is not possible output the line “such number is impossible!” For each line of input there will be only a single line of output. The output will always be in decimal number system.(有可能是没有结果的情况) 原文链接:

//数学
#include <iostream>
#include<string>
using namespace std;

const int MAXN = 0x3f3f3f3f;

int change(char c) {//将字符转换成10进制数字
	if (c >= 'A' && c <= 'Z')
		return c - 'A' + 10;
	else if (c >= 'a' && c <= 'z')
		return c - 'a' + 36;
	else
		return c - '0';
}

int main() {
	string str;
	int n,tmp,sum,cur;
	bool flag;
	while (cin >> str) {
		sum = 0,flag=1;
		cur = -MAXN;//保存基数
		n = str.size() - 1;//字符串长度
		for (int i = n; i >= 0; i--) {
			tmp = change(str[i]);
			sum += tmp;
			if (tmp > cur)//更新基数
				cur = tmp;
		}
		for (int i = cur + 1; i <= 62; i++) {//遍历满足条件的最小基数
			if (sum % (i - 1) == 0) {
				cout << i << endl;
				flag = 0;
				break;
			}
		}
		if(flag)
			printf("such number is impossible!\n");
	}
	return 0;
}

C - Primitive Roots

题目

We say that integer x, 0 < x < p, is a primitive root modulo odd prime p if and only if the set { (xi mod p) | 1 <= i <= p-1 } is equal to { 1, …, p-1 }. For example, the consecutive powers of 3 modulo 7 are 3, 2, 6, 4, 5, 1, and thus 3 is a primitive root modulo 7.
Write a program which given any odd prime 3 <= p < 65536 outputs the number of primitive roots modulo p.

Input

Each line of the input contains an odd prime numbers p. Input is terminated by the end-of-file seperator.

Output

For each p, print a single number that gives the number of primitive roots in a single line.

Sample

InputcopyOutputcopy
23 31 79 10 8 24

解析

原文链接:原根与欧拉公式

数论题,涉及欧拉公式
先介绍一个概念:
设m是正整数,a是整数,若a模m的阶等于φ(m),则称a为模m的一个原根。(其中φ(m)表示m的欧拉函数)
假设一个数g对于P来说是原根,那么gi mod P的结果两两不同,且有 1<g<P, 0<i<P,那么g可以称为是P的一个原根,归根到底就是g(P-1) = 1 (mod P)当且仅当指数为P-1的时候成立.(这里P是素数).
选自百度百科
结合到本题,x就是p的一个原根,那我们只需要找到满足xp-1=1(mod P)这个式子就可以,这个式子也就是欧拉公式的φ(p-1)
欧拉公式链接:

#include<iostream>
using namespace std;
typedef long long ll;
ll Euler(ll n){
	ll res=n;
	for(ll i=2;i*i<=n;i++)
	{
		if(n%i==0){
			n/=i;
			res=res-res/i;
		}
		while(n%i==0)n/=i;
	}
	if(n>1)res=res-res/n;
	return res;
}
int main()
{
	int p;
	while(cin>>p)
	{
		cout<<Euler(p-1)<<endl;
	}
	return 0;
}

D - Sumdiv

题目

Consider two natural numbers A and B. Let S be the sum of all natural divisors of A^B. Determine S modulo 9901 (the rest of the division of S by 9901).

Input

The only line contains the two natural numbers A and B, (0 <= A,B <= 50000000)separated by blanks.

Output

The only line of the output will contain S modulo 9901.

Sample

InputcopyOutputcopy
2 315

Hint

2^3 = 8.
The natural divisors of 8 are: 1,2,4,8. Their sum is 15.
15 modulo 9901 is 15 (that should be output).

解析

终于遇到一个学过且自己做出来的题了,但最后看了一下题解后发现还可以优化一下,贴出完整思路,注意等比数列求解而不是套公式自己码一遍代码再推理一下就明白了

(1) 整数的唯一分解定理:

  任意正整数都有且只有一种方式写出其素因子的乘积表达式。

  A=(p1^k1)*(p2^k2)*(p3^k3)*....*(pn^kn)   其中pi均为素数

(2) 约数和公式:

对于已经分解的整数A=(p1k1)*(p2k2)*(p3k3)*…*(pnkn)

有A的所有因子之和为

S = (1+p1+p1^2+p1^3+...p1^k1) * (1+p2+p2^2+p2^3+….p2^k2) * (1+p3+ p3^3+…+ p3^k3) * .... * (1+pn+pn^2+pn^3+...pn^kn)

(3) 同余模公式:

(a+b)%m=(a%m+b%m)%m

(ab)%m=(a%mb%m)%m

#include<iostream>
#include<algorithm>
#include<math.h>
using namespace std;
struct Data {
	int num, base;
}p[1000];
int len = 0;
long long Pow(long long base, long long n)
{
	long long ans = 1;
	while (n)
	{
		if (n & 1)
			ans = ans*base%9901;
		base = base*base%9901;
		n >>= 1;
	}
	return ans;
}
long long updata(long long pn, long long pm)  ///递归二分求等比数列的和
{
	if (pm == 0)
	{
		return 1;
	}
	if (pm % 2)
	{
		return (updata(pn, pm / 2) * (1 + Pow(pn, pm / 2 + 1))) % 9901;  /// 当pm为奇数时,有公式来求等比数列的和 
		//(1 + p + p^2 +...+ p^(n/2)) * (1 + p^(n/2+1)) 
	}
	else
	{
		return (updata(pn, pm / 2 - 1) * (1 + Pow(pn, pm / 2 + 1)) + Pow(pn, pm / 2)) % 9901;  ///当pm为偶数时,有公式来求等比数列的和 
		//(1 + p + p^2 +...+ p^(n/2-1)) * (1+p^(n/2+1)) + p^(n/2); 
	}
}
int main()
{
	int a, b;
	scanf("%d%d", &a, &b);
	for (int i = 2; i <= a; i++)
	{
		if (a % i == 0)
		{
			p[len].num = 0;
			p[len].base = i;
			while (a % i == 0)
			{
				p[len].num+=b;
				a /= i;
			}
			len++;
		}
	}
	long long ans = 1;
	for (int i = 0; i < len; i++)
	{
		ans = ans * updata(p[i].base, p[i].num)%9901;
	}
	printf("%lld", ans);
	return 0;
}

E - C Looooops

题目

A Compiler Mystery: We are given a C-language style for loop of type

for (variable = A; variable != B; variable += C)

  statement;

I.e., a loop which starts by setting variable to value A and while variable is not equal to B, repeats statement followed by increasing the variable by C. We want to know how many times does the statement get executed for particular values of A, B and C, assuming that all arithmetics is calculated in a k-bit unsigned integer type (with values 0 <= x < 2^k) modulo 2^k.

Input

The input consists of several instances. Each instance is described by a single line with four integers A, B, C, k separated by a single space. The integer k (1 <= k <= 32) is the number of bits of the control variable of the loop and A, B, C (0 <= A, B, C < 2k) are the parameters of the loop.

The input is finished by a line containing four zeros.

Output

The output consists of several lines corresponding to the instances on the input. The i-th line contains either the number of executions of the statement in the i-th instance (a single integer number) or the word FOREVER if the loop does not terminate.

Sample

InputcopyOutputcopy
3 3 2 16 3 7 2 16 7 3 2 16 3 4 2 16 0 0 0 0 0 2 32766 FOREVER

解析

在mod 2^k 范围内,(a+xc)%(2^k) = b 即(a+xc)= y(2^k) + b (x,y均为未知整数)

整理得:xc - y(2^k) = b-a 非常符合拓展欧几里得形式 ax+by=gcd(a,b)

当b-a是gcd(c,2^k))时,有解。

若有解,则利用拓展欧几里得得出特解x0,然后x0要乘上(b-a)/gcd(c,2^k)

令t= (2k)/gcd(c,2k);

通解x=x0+ k *t,明显当x大于t时,都可以再让k减1,因此最小正整数解x就是x%t

#include <stdio.h>
#define LL long long
 
LL exgcd(LL a,LL b,LL &x,LL &y)
{
    if(!b)return x=1,y=0,a;
    LL d=exgcd(b,a%b,x,y);
    LL c=x;
    return x=y,y=c-a/b*y,d;
}
 
int main()
{
    LL a,b,c,k,x,y;
    while(scanf("%I64d%I64d%I64d%I64d",&a,&b,&c,&k),a+b+c+k)
    {
        k=((LL)1<<k);
        LL d=exgcd(c,k,x,y);
        if((b-a)%d)
            printf("FOREVER\n");
        else
        {
            x=(b-a)/d*x;
            LL s=k/d;
            x=(x%s+s)%s;
            printf("%I64d\n",x);
        }
    }
}

F - The Embarrassed Cryptographer

题目

The young and very promising cryptographer Odd Even has implemented the security module of a large system with thousands of users, which is now in use in his company. The cryptographic keys are created from the product of two primes, and are believed to be secure because there is no known method for factoring such a product effectively.
What Odd Even did not think of, was that both factors in a key should be large, not just their product. It is now possible that some of the users of the system have weak keys. In a desperate attempt not to be fired, Odd Even secretly goes through all the users keys, to check if they are strong enough. He uses his very poweful Atari, and is especially careful when checking his boss’ key.

Input

The input consists of no more than 20 test cases. Each test case is a line with the integers 4 <= K <= 10100 and 2 <= L <= 106. K is the key itself, a product of two primes. L is the wanted minimum size of the factors in the key. The input set is terminated by a case where K = 0 and L = 0.

Output

For each number K, if one of its factors are strictly less than the required L, your program should output “BAD p”, where p is the smallest factor in K. Otherwise, it should output “GOOD”. Cases should be separated by a line-break.

Sample

InputcopyOutputcopy
143 10 143 20 667 20 667 30 2573 30 2573 40 0 0GOOD BAD 11 GOOD BAD 23 GOOD BAD 31

解析

原文链接:素数筛+高精度取模

给定一个大数str,str是两个大素数的乘积的值,再给定一个int内的数n,问这两个大素数中最小的一个是否小于n,如果小于则输出GOOD,否则输出BAD和两个素数中最小的。

思路:先用素数筛把小于1100000的素数都找出来。然后把str转化为一堆千进制。对于每一个千进制,把i从2到n遍历一遍即可

主要利用qk数组和同余模定理。
例如要验证123是否被3整除,只需求模124%3
但当123是一个大数时,就不能直接求,只能通过同余模定理对大数“分块”间接求模
具体做法是:
先求1%3 = 1
再求(110+2)%3 = 0
再求 (0
10+4)% 3 = 1
那么就间接得到124%3=1,这是显然正确的
而且不难发现, (1*10+2)*10+4 = 124
这是在10进制下的做法,千进制也同理,10改为1000就可以了。

#include <stdio.h>
#include <math.h>
#include <string.h>
#include <stdlib.h>
#include <iostream>
#include <sstream>
#include <algorithm>
#include <set>
#include <queue>
#include <stack>
#include <map>
using namespace std;
typedef long long LL;
const int inf=0x3f3f3f3f;
const double eps=1e-10;
const double pi= acos(-1.0);
const int MAXN=1e6+10;
int prime[MAXN]={2,3,5};
int qk[1010];
//素数筛
void is_prime()
{
    int i,j;
    int flag=0;
    int gcd=2;
    int k=3;
    for(i=7;i<MAXN;i+=gcd){
        flag=0;
        gcd=6-gcd;
        for(j=0;prime[j]*prime[j]<=i;j++){
            if(i%prime[j]==0){
                flag=1;
                break;
            }
        }
        if(!flag)
            prime[k++]=i;
    }
}
//高精度K对p求模,因数检查(整除)
int mod(int *K,int m,int len)
{
   int res=0;
   for(int i=len-1;i>=0;i--)//千进制K是逆序存放,因为计算起来方便
    res=(res*1000+K[i])%m; //同余模定理
   if(!res) return 0; //K被整除 
   else  return 1;
}
 
int main()
{
    char str[1010];
    int n,i,j;
    int flag;
    is_prime();
    while(~scanf("%s %d",str,&n)){
        if(str[0]=='0'&&n==0) break;
        memset(qk,0,sizeof(qk));
        int len=strlen(str);
        int ii=0;
        for(int i=len-1;i>=0;i-=3){//把str转换为千进制qk,其中qk局部顺序,全局倒序 
                                   //如str=1234567=[  1][234][567] ,则qk=[567][234][1  ]  
            if(i>=2)
            qk[ii]=(str[i]-'0')+(str[i-1]-'0')*10+(str[i-2]-'0')*100;
            else if(i==1)
            qk[ii]=(str[i]-'0')+(str[i-1]-'0')*10;
            else if(i==0)
            qk[ii]=(str[i]-'0');
            ii++;
        }
        int len_qk=(len+2)/3;
        int qMin=0;//能整除qk且比n小的在prime中的最小素数下标
        flag=1;
        while(prime[qMin]<n){//枚举prime中比L小的素数  
            if(!mod(qk,prime[qMin],len_qk)){
                flag=0;
                printf("BAD %d\n",prime[qMin]);
                break;
            }
            qMin++;
        }
        if(flag)
            puts("GOOD");
    }
    return 0;
}

G - Semi-prime H-numbers

题目

This problem is based on an exercise of David Hilbert, who pedagogically suggested that one study the theory of 4n+1 numbers. Here, we do only a bit of that.

An H-number is a positive number which is one more than a multiple of four: 1, 5, 9, 13, 17, 21,… are the H-numbers. For this problem we pretend that these are the only numbers. The H-numbers are closed under multiplication.

As with regular integers, we partition the H-numbers into units, H-primes, and H-composites. 1 is the only unit. An H-number h is H-prime if it is not the unit, and is the product of two H-numbers in only one way: 1 × h. The rest of the numbers are H-composite.

For examples, the first few H-composites are: 5 × 5 = 25, 5 × 9 = 45, 5 × 13 = 65, 9 × 9 = 81, 5 × 17 = 85.

Your task is to count the number of H-semi-primes. An H-semi-prime is an H-number which is the product of exactly two H-primes. The two H-primes may be equal or different. In the example above, all five numbers are H-semi-primes. 125 = 5 × 5 × 5 is not an H-semi-prime, because it’s the product of three H-primes.

Input

Each line of input contains an H-number ≤ 1,000,001. The last line of input contains 0 and this line should not be processed.

Output

For each inputted H-number h, print a line stating h and the number of H-semi-primes between 1 and h inclusive, separated by one space in the format shown in the sample.

Sample

InputcopyOutputcopy
21 85 789 021 0 85 5 789 62

解析

题意:
这个问题是基于戴维·希尔伯特(David Hilbert)的一项练习得出的,戴维·希尔伯特(David Hilbert)在教学法上建议对4n + 1数的理论进行研究。在这里,我们只做一点。

H数是一个正数,是四的整数倍:1、5、9、13、17、21,…是H数。对于这个问题,我们假装这些是唯一的数字。H数在乘法下是闭合的。

与常规整数一样,我们将H数划分为单位,H素数和H组合。1是唯一的单位。如果H数h不是单位,则为H素数,并且仅以一种方式为两个H数的乘积:1×h。其余数字是H组合的。

例如,前几个H复合材料为:5×5 = 25、5×9 = 45、5×13 = 65、9×9 = 81、5×17 = 85。

您的任务是计算H半素数。H半素数是一个H数,正好是两个H素数的乘积。两个H-素数可以相等或不同。在上面的示例中,所有五个数字均为H-半质数。125 = 5×5×5不是H-半素数,因为它是三个H-素数的乘积。

输入
输入的每一行包含一个H数≤1,000,001。输入的最后一行包含0,并且不应处理此行。

输出
对于每个输入的H数h,以示例中显示的格式打印一行h,并在1和h之间(含1和h)打印H半素数。

这个题目就相当于让先筛选H-素数, 找0到h中有多少个数是两个h-素数乘到一起的,然后这个时候我们就改进一下筛选素数的方法, 如果i是一个H-素数,那么和i属于同一类的一定是i * (4x + 1) , 也就是将i乘上(4x + 1) , 题目规定(4x + 1)是h数, 所以i * (4x + 1)一定是H数 但一定不是H-素数,以为现在他有两个因子i和4i + 1 , 我们就这样构造一下,将线性筛选素数改改,然后就出来了

两套代码:

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <vector>
#define maxn 1000010
 
typedef long long int ll;
using namespace std;
vector<int> v;//存放4n+1的数
bool isHP[maxn];
int ans[maxn];
void init()
{
    memset(isHP,true,sizeof(isHP));
    for(int i=5; i<maxn; i+=4)
    {
        if(isHP[i])
        {
            v.push_back(i);
            for(int j=i+i;j<maxn;j+=i)
            {
                if(j%4==1)
                    isHP[j]=false;
            }
        }
    }
    for(int i=0;i<v.size();i++)
    {
        if(v[i]>1010)//只需v[i]小于maxn的开方
            break;
        for(int j=i;j<v.size();j++)
        {
            int temp=v[i]*v[j];//temp必定是4n+1形式(易证),无需判断
            if(temp>=maxn)
                break;
            ans[temp]=1;
        }
    }
   for(int i=1;i<maxn;i++)
   {
       ans[i]+=ans[i-1];
   }
}
int main()
{
    init();
    int n;
    while(scanf("%d",&n)&&n)
    {
        printf("%d %d\n",n,ans[n]);
    }
    return 0;
}
#include <iostream>
using namespace std;
const int N = 1e6 + 10 ;
int vis[N] , prime[N] ; 
int cnt[N] ;
int st[N] ;
int tot ;
void get()
{
	for(int i = 5 ;i < N ;i += 4) 
	 {
	 	if(!vis[i]) 
	 	prime[++ tot] = i ;
	 	for(int j = i ;j < N ;j += 4 * i)
	 	 vis[j] = true ;
	 }
	 for(int i = 1 ;i <= tot ;i ++)
	  for(int j =  1 ;j <= i && prime[i] * prime[j] < N ;j ++)
	   st[prime[i] * prime[j]] = 1 ;
	for(int i = 1 ;i < N ;i ++)
	 cnt[i] = cnt[i - 1] + st[i] ; 
}
int main()
{
	get() ;
	int a , b ;
	while(cin >> a && a != 0)
	 cout << a << " " << cnt[a] << endl ;
	return 0;
}

H - Raising Modulo Numbers

题目

People are different. Some secretly read magazines full of interesting girls’ pictures, others create an A-bomb in their cellar, others like using Windows, and some like difficult mathematical games. Latest marketing research shows, that this market segment was so far underestimated and that there is lack of such games. This kind of game was thus included into the KOKODáKH. The rules follow:

Each player chooses two numbers Ai and Bi and writes them on a slip of paper. Others cannot see the numbers. In a given moment all players show their numbers to the others. The goal is to determine the sum of all expressions AiBi from all players including oneself and determine the remainder after division by a given number M. The winner is the one who first determines the correct result. According to the players’ experience it is possible to increase the difficulty by choosing higher numbers.

You should write a program that calculates the result and is able to find out who won the game.

Input

The input consists of Z assignments. The number of them is given by the single positive integer Z appearing on the first line of input. Then the assignements follow. Each assignement begins with line containing an integer M (1 <= M <= 45000). The sum will be divided by this number. Next line contains number of players H (1 <= H <= 45000). Next exactly H lines follow. On each line, there are exactly two numbers Ai and Bi separated by space. Both numbers cannot be equal zero at the same time.

Output

For each assingnement there is the only one line of output. On this line, there is a number, the result of expression

(A1B1+A2B2+ … +AHBH)mod M.

Sample

InputcopyOutputcopy
3 16 4 2 3 3 4 4 5 5 6 36123 1 2374859 3029382 17 1 3 18132 2 13195 13

解析

套用快速幂取模的模板就行

终于遇到个水题,感动死了

#include<iostream>
#include<cstdio>
using namespace std;
typedef unsigned long long int ll;
int Pow(int a,int b,int c)
{
   int ans=1;
   a=a%c;
   while(b!=0)
   {
     if(b&1) ans=(ans*a)%c;
     b>>=1;
     a=(a*a)%c;
  }
   return ans;
}
int main()
{
        int t;
        cin>>t;
        while(t--)
        {
            int m,n;
            int ans=0;
            cin>>m>>n;
            for(int i=0;i<n;i++)
            {
                int a,b;
                cin>>a>>b;
                ans+=Pow(a,b,m);
                ans%=m;
            }
            cout<<ans<<endl;
        }
}

I - Fibonacci

题目

In the Fibonacci integer sequence, F0 = 0, F1 = 1, and Fn = Fn − 1 + Fn − 2 for n ≥ 2. For example, the first ten terms of the Fibonacci sequence are:

0, 1, 1, 2, 3, 5, 8, 13, 21, 34, …

An alternative formula for the Fibonacci sequence is

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qFrDznjI-1668356774529)(https://vj.csgrandeur.cn/23da167d8116d97497f11a1e8ecd74fa?v=1667907883)].

Given an integer n, your goal is to compute the last 4 digits of Fn.

Input

The input test file will contain multiple test cases. Each test case consists of a single line containing n (where 0 ≤ n ≤ 1,000,000,000). The end-of-file is denoted by a single line containing the number −1.

Output

For each test case, print the last four digits of Fn. If the last four digits of Fn are all zeros, print ‘0’; otherwise, omit any leading zeros (i.e., print Fn mod 10000).

Sample

InputcopyOutputcopy
0 9 999999999 1000000000 -10 34 626 6875

解析

矩阵快速幂模板题了,poj太老了,提交好几次就是编译错误

#include<iostream>
using namespace std;
struct martix 
{
	int m[2][2]={0};
	martix operator*(const martix& a)
	{
		martix c;
		memset(c.m, 0, sizeof(c.m));
		for (int i = 0; i < 2; i++)
			for (int j = 0; j < 2; j++)
				for (int k = 0; k < 2; k++)
					c.m[i][j] += (m[i][k]%10000)*(a.m[k][j]%10000)%10000;
		return c;
	}
};
int main()
{
	int n;
	while (cin >> n && n != -1)
	{
		martix ans={{1,0,0,1}}, a = {{1,1,1,0}};
		n += 1;
		while (n)
		{
			if (n & 1)ans = ans * a;
			a = a * a;
			n >>= 1;
		}
		cout << ans.m[1][1]%10000 << endl;
	}
	return 0;
}

J - Pseudoprime numbers

题目

Fermat’s theorem states that for any prime number p and for any integer a > 1, ap = a (mod p). That is, if we raise a to the pth power and divide by p, the remainder is a. Some (but not very many) non-prime values of p, known as base-a pseudoprimes, have this property for some a. (And some, known as Carmichael Numbers, are base-a pseudoprimes for all a.)

Given 2 < p ≤ 1000000000 and 1 < a < p, determine whether or not p is a base-a pseudoprime.

Input

Input contains several test cases followed by a line containing “0 0”. Each test case consists of a line containing p and a.

Output

For each test case, output “yes” if p is a base-a pseudoprime; otherwise output “no”.

Sample

InputcopyOutputcopy
3 2 10 3 341 2 341 3 1105 2 1105 3 0 0 no no yes no yes yes

解析

题意:给出 p 和 a,若 a^p 对 p 取余且 p 不是素数,则输出 yes,否则输出 no

思路:大整数快速幂求模,加素数判断,此处采用朴素素数求法

#include<iostream>
#include<cstdio>
#include<cstring>
#define LL long long
using namespace std;
LL Pow(LL a, LL b, LL m)
{
    LL res=1;
    while(b)
    {
        if(b&1)
            res=(res*a)%m;
        a=(a*a)%m;
        b>>=1;
    }
    return res;
}
bool prime(LL n)
{
    if(n==2)
        return true;
 
    for(LL i=2;i*i<=n;i++)
        if(n%i==0)
            return false;
    return true;
}
int main()
{
    LL p,a;
    while(scanf("%lld%lld",&p,&a)!=EOF&&(p+a))
    {
        if( !prime(p) && Pow(a,p,p)==a )
            printf("yes\n");
        else
            printf("no\n");
    }
    return 0;
}

ut “no”.

Sample

InputcopyOutputcopy
3 2 10 3 341 2 341 3 1105 2 1105 3 0 0 no no yes no yes yes

解析

题意:给出 p 和 a,若 a^p 对 p 取余且 p 不是素数,则输出 yes,否则输出 no

思路:大整数快速幂求模,加素数判断,此处采用朴素素数求法

#include<iostream>
#include<cstdio>
#include<cstring>
#define LL long long
using namespace std;
LL Pow(LL a, LL b, LL m)
{
    LL res=1;
    while(b)
    {
        if(b&1)
            res=(res*a)%m;
        a=(a*a)%m;
        b>>=1;
    }
    return res;
}
bool prime(LL n)
{
    if(n==2)
        return true;
 
    for(LL i=2;i*i<=n;i++)
        if(n%i==0)
            return false;
    return true;
}
int main()
{
    LL p,a;
    while(scanf("%lld%lld",&p,&a)!=EOF&&(p+a))
    {
        if( !prime(p) && Pow(a,p,p)==a )
            printf("yes\n");
        else
            printf("no\n");
    }
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值