HPU算法协会公开课第二期: 【基础算法2】(快速幂+二分)

HPU算法协会公开课第二期: 【基础算法2】(快速幂+二分)

快速幂板子
二分查找模板

A - 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 Input
3 2
10 3
341 2
341 3
1105 2
1105 3
0 0
Sample Output
no
no
yes
no
yes
yes

若p不是素数并且a^p = a (mod p),输出yes,否则输出no。将mod改成p即可。
快速幂

#include
#include
using namespace std;
typedef long long ll;
bool pd(ll num){/*速度最快*/ 
    if(num==1) return 0;
    if(num==2||num==3) return 1;   
    if(num%6!=1&&num%6!=5) return 0 ;  
    int tmp=sqrt(num);
    for(int i=5;i<=tmp;i+=6){
    	if(num%i==0||num%(i+2)==0) return 0;
    }
    return 1 ;
}
ll qmi(ll a,ll k,ll mod){//快速幂 算a的k次方 
	ll res=1;
	while(k){
		if(k&1/*判断是否为奇数 */) res=(ll)res*a%mod;
		a=(ll)a*a%mod;
		k>>=1/*实际上将K除以2*/;
	}
	return res;
}
int main(){
	ll p,a;
	while(cin>>p>>a&&p&&a){
		if(!pd(p)&&qmi(a,p,p)==a) cout<<"yes"<<'\n';
		else cout<<"no"<<'\n';
	}
	return 0;
}

B - 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 Input
3
16
4
2 3
3 4
4 5
5 6
36123
1
2374859 3029382
17
1
3 18132
Sample Output
2
13195
13

每组给出a,b的值,求a1^b1+ a2^b2+ …+an^bn之和mod M的值。
快速幂

#include
#include
using namespace std;
typedef long long ll;

ll qmi(ll a,ll k,ll mod){ 
	ll res=1;
	while(k){
		if(k&1) res=(ll)res*a%mod;
		a=(ll)a*a%mod;
		k>>=1;
	}
	return res;
}
int main(){
	int t;
	cin>>t;
	while(t--){
		int ans=0,m,h;
		cin>>m>>h;
		while(h--){
			int a,b;
			cin>>a>>b;
			ans=(ans+qmi(a,b,m))%m;
		}
		cout<<ans<<'\n';
	}
	return 0;
}

C - Key Set

soda has a set S with n integers {1,2,…,n}. A set is called key set if the sum of integers in the set is an even number. He wants to know how many nonempty subsets of S are key set.
Input
There are multiple test cases. The first line of input contains an integer T (1≤T≤105), indicating the number of test cases. For each test case:

The first line contains an integer n (1≤n≤109), the number of integers in the set.
Output
For each test case, output the number of key sets modulo 1000000007.
Sample Input
4
1
2
3
4
Sample Output
0
1
3
7

给你一个具有n个元素的集合S,问集合S的非空子集中元素和为偶数的非空子集有多少个,数据大,取模1000000007。
高中公式:2^(n-1)-1
快速幂

#include
using namespace std;
typedef long long ll;
ll qmi(ll a,ll k,ll mod){ 
	ll res=1;
	while(k){
		if(k&1/*判断是否为奇数 */) res=(ll)res*a%mod;
		a=(ll)a*a%mod;
		k>>=1/*实际上将K除以2*/;
	}
	return res;
}
int main(){
    int t;
	cin>>t;
    while(t--){
    	int n;
        cin>>n;
        cout<<qmi(2,n-1,1e9+7)-1<<'\n';
    }
    return 0;
}

D - Distribution money

AFA want to distribution her money to somebody.She divide her money into n same parts.One who want to get the money can get more than one part.But if one man’s money is more than the sum of all others’.He shoule be punished.Each one who get a part of money would write down his ID on that part.
Input
There are multiply cases.
For each case,there is a single integer n(1<=n<=1000) in first line.
In second line,there are n integer a1,a2…an(0<=ai<10000)ai is the the ith man’s ID.
Output
Output ID of the man who should be punished.
If nobody should be punished,output -1.
Sample Input
3
1 1 2
4
2 1 4 3
Sample Output
1
-1

随意排队领薪金,如果一个人领的超过其他人的总和那么这个人将受到惩罚,输出这个人的工号,否则输出-1,总共薪金是n,某个人可能领x,那么其他人的总和就是n-x,如果x>n-x即x>n/2,那么这个人领的薪金就超过其他人了。

#include
#include
using namespace std;
typedef long long ll;
int a[10010];
int main(){
	int n;
	while(cin>>n){
		memset(a,0,sizeof(a));
		int flag=1;
		for(int i=1;i<=n;i++){
			int x;
			cin>>x;
			a[x]++;
		}
		for(int i=1;i<=10000;i++){
			if(a[i]>n/2){
				cout<<i<<'\n';
				flag=0;
				break;
			}
		}
		if(flag) cout<<-1<<'\n';
	}
	return 0;
}

E - Rightmost Digit

Given a positive integer N, you should output the most right digit of N^N.
Input
The input contains several test cases. The first line of the input is a single integer T which is the number of test cases. T test cases follow.
Each test case contains a single positive integer N(1<=N<=1,000,000,000).
Output
For each test case, you should output the rightmost digit of N^N.
Sample Input
2
3
4
Sample Output
7
6
Hint
In the first case, 3 * 3 * 3 = 27, so the rightmost digit is 7.
In the second case, 4 * 4 * 4 * 4 = 256, so the rightmost digit is 6.

输出n^n的最后一位数字。
快速幂

#include
#define ull unsigned long long
#define pi acos(-1)
using namespace std;
typedef long long ll;
ll qmi(ll a,ll k,ll mod){//快速幂 算a的k次方 
	ll res=1;
	while(k){
		if(k&1/*判断是否为奇数 */) res=(ll)res*a%mod;
		a=(ll)a*a%mod;
		k>>=1/*实际上将K除以2*/;
	}
	return res;
}
int main(){
	int t;
	cin>>t;
	while(t--){
		ll n;
		cin>>n;
		cout<<qmi(n,n,10)<<'\n';
	}
	return 0;
}

F - 人见人爱A^B

求A^B的最后三位数表示的整数。
说明:A^B的含义是“A的B次方”
Input
输入数据包含多个测试实例,每个实例占一行,由两个正整数A和B组成(1<=A,B<=10000),如果A=0, B=0,则表示输入数据的结束,不做处理。
Output
对于每个测试实例,请输出A^B的最后三位表示的整数,每个输出占一行。
Sample Input
2 3
12 6
6789 10000
0 0
Sample Output
8
984
1

快速幂,mod1000就行了。

#include
using namespace std;
typedef long long ll;
const ll mod(1000);
ll qmi(ll a,ll k){//快速幂 算a的k次方 
	ll res=1;
	while(k){
		if(k&1/*判断是否为奇数 */) res=(ll)res*a%mod;
		a=(ll)a*a%mod;
		k>>=1/*实际上将K除以2*/;
	}
	return res;
}
int main(){
	int a,k;
	while(cin>>a>>k&&a&&k){
		cout<<qmi(a,k)<<'\n';
	}
	return 0;
}

G - Trailing Zeroes (III)

You task is to find minimal natural number N, so that N! contains exactly Q zeroes on the trail in decimal notation. As you know N! = 12…*N. For example, 5! = 120, 120 contains one zero on the trail.

Input
Input starts with an integer T (≤ 10000), denoting the number of test cases.

Each case contains an integer Q (1 ≤ Q ≤ 108) in a line.

Output
For each case, print the case number and N. If no solution is found then print ‘impossible’.

Sample Input
3

1

2

5

Sample Output
Case 1: 5

Case 2: 10

Case 3: impossible

给你q,让你找到n,使得n!中含有q个0。就是要找到乘出来可以得到多少个整10,我们可知5*2=10,要找到有多少个10,必然要找到有多少个5。如何求出n的阶乘中有多少个0,具体看代码。选取合适的范围进行二分查找即可。

#include
#define ull unsigned long long
#define pi acos(-1)
using namespace std;
typedef long long ll;
int q,l,r;
ll f(int m){//寻找有几个0,如5!有一个0,10!有两个0 
	ll ans=0;
	while(m){
		ans+=(m/5);
		m/=5;
	}
	return ans;
}//妙啊 
int half(int l,int r){
	while(l<r){
		int mid=(l+r)>>1;
		if(f(mid)>=q) r=mid;
		else l=mid+1;
	}
	return l;
}
int main(){
	int t;
	cin>>t;
	for(int k=1;k<=t;k++){
		cin>>q;
		l=1,r=5e8;
		int ans=half(l,r);
		if(f(ans)==q) printf("Case %d: %d\n",k,ans);
		else printf("Case %d: impossible\n",k);
	}
	return 0;
}

H - Pie

My birthday is coming up and traditionally I’m serving pie. Not just one pie, no, I have a number N of them, of various tastes and of various sizes. F of my friends are coming to my party and each of them gets a piece of pie. This should be one piece of one pie, not several small pieces since that looks messy. This piece can be one whole pie though.

My friends are very annoying and if one of them gets a bigger piece than the others, they start complaining. Therefore all of them should get equally sized (but not necessarily equally shaped) pieces, even if this leads to some pie getting spoiled (which is better than spoiling the party). Of course, I want a piece of pie for myself too, and that piece should also be of the same size.

What is the largest possible piece size all of us can get? All the pies are cylindrical in shape and they all have the same height 1, but the radii of the pies can be different.
Input
One line with a positive integer: the number of test cases. Then for each test case:
—One line with two integers N and F with 1 <= N, F <= 10 000: the number of pies and the number of friends.
—One line with N integers ri with 1 <= ri <= 10 000: the radii of the pies.
Output
For each test case, output one line with the largest possible volume V such that me and my friends can all get a pie piece of size V. The answer should be given as a floating point number with an absolute error of at most 10^(-3).
Sample Input
3
3 3
4 3 3
1 24
5
10 5
1 4 2 3 4 5 6 5 4 2
Sample Output
25.1327
3.1416
50.2655

分到最大馅饼的体积是:所有馅饼体积之和/(F+1);(为什么不能是直接所有馅饼之和/(F+1)呢?因为每人只能分到一块,如果讲究平均分的话,一个人分到的就是拼凑起来的“最大的体积”,一个人甚至可能得到超过一块馅饼)最小即为0,然后我们对这两个最大最小值采用二分方法,求出中间符合最大的体积。那么怎么判断那个值就是最大的体积呢?让每个馅饼的体积/能分到最大的体积=能分到的人数,然后将每个馅饼能分到的人数相加,将该人数与F+1做判断比较//转自「聪明绝顶的你与即将秃头的我」

#include
#define ull unsigned long long
#define pi acos(-1)
using namespace std;
typedef long long ll;
const int maxn = 1e7+5;
double v[10008];
int main(){
	int t;
	cin>>t;
	while(t--){
		int n,f;
		double right,left=0.0,mid;
		cin>>n>>f;
		f++;
		for(int i=1;i<=n;i++){
			int r;
			cin>>r;
			v[i]=pi*r*r;
			right+=v[i];
		}
		right/=f;
		while(right-left>1e-6){
			int sum=0;
			mid=(right+left)/2.0;
			for(int i=1;i<=n;i++) sum+=(int)(v[i]/mid);
			if(sum>=f) left=mid;
			else right=mid;
		}
		printf("%.4lf\n",mid);
	}
	return 0;
}

I - Can you solve this equation?

Now,given the equation 8x^4 + 7x^3 + 2x^2 + 3x + 6 == Y,can you find its solution between 0 and 100;
Now please try your lucky.
Input
The first line of the input contains an integer T(1<=T<=100) which means the number of test cases. Then T lines follow, each line has a real number Y (fabs(Y) <= 1e10);
Output
For each test case, you should just output one real number(accurate up to 4 decimal places),which is the solution of the equation,or “No solution!”,if there is no solution for the equation between 0 and 100.
Sample Input
2
100
-4
Sample Output
1.6152
No solution!

给你一个等式和y的值,让你求x(精确到4位小数),x为0~100之间的值。
二分即可

#include
#define ull unsigned long long
#define pi acos(-1)
using namespace std;
typedef long long ll;
const int maxn = 1e7+5;
double f(double x){
    return 8*x*x*x*x+7*x*x*x+2*x*x+3*x+6;
}
int main(){
	int t;
	cin>>t;
	while(t--){
		int y;
		cin>>y;
		double l=0,r=100,mid,ans=-1;
		for(int i=0;i<50;i++){
            mid=(l+r)/2;
            if(abs(f(mid)-y)<=1e-6){
                ans=mid;
                break;
            }
            else if(f(mid)>y) r=mid;    
            else l=mid;
        }
		if(ans==-1) printf("No solution!\n");
		else printf("%.4lf\n",mid);
	}
	return 0;
}

J - Subsequence

A sequence of N positive integers (10 < N < 100 000), each of them less than or equal 10000, and a positive integer S (S < 100 000 000) are given. Write a program to find the minimal length of the subsequence of consecutive elements of the sequence, the sum of which is greater than or equal to S.
Input
The first line is the number of test cases. For each test case the program has to read the numbers N and S, separated by an interval, from the first line. The numbers of the sequence are given in the second line of the test case, separated by intervals. The input will finish with the end of file.
Output
For each the case the program has to print the result on separate line of the output file.if no answer, print 0.
Sample Input
2
10 15
5 1 3 5 10 7 4 9 2 8
5 11
1 2 3 4 5
Sample Output
2
3

T组,每组有N个序列和S,输出序列和大于等于S的最短序列长度,如无符合输出0。
我用的尺取法

#include
#define ull unsigned long long
#define pi acos(-1)
using namespace std;
typedef long long ll;
const int maxn = 1e7+5;
int a[100005];
int main(){
    int t;
    cin>>t;
    while(t--){
        int n,s;
        cin>>n>>s;
        int min=n,sum=0;
        for(int i=0;i<n;i++) cin>>a[i];
        for(int i=0,j=0;;){
            while(i<n&&sum<s) sum+=a[i++];    
            if(sum<s) break;
            if(min>(i-j)) min=i-j;   
            sum-=a[j++];
        }
        if(min>=n&&sum<s) min=0;
        cout<<min<<'\n';
    }
}

你可能感兴趣的:(19级训练)