第二次公开课(快速幂,二分)

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.

题意就是a^p=a(mod p)且p不为素数时,返回yes,否则返回no,利用快速幂。

#include
#include
using namespace std;
typedef long long ll;
bool isprime(long long num)
{
    for(int i=2;i*i>=1;
	}
	return ans==t;
}

int main()
{
	int p,a;
	while(scanf("%ld %ld",&p,&a)!=EOF)
	{
		if(p==0 && a==0) break;
		if(!isprime(p) && poww(p,a))        
			printf("yes\n");
		else
			printf("no\n");
	}
	return 0;
}

快速幂模板:讲指数化为二进制进行计算

int Pow(int a,int b){
    int ans = 1;
    int base = a;
    while(b){
        if(b & 1) ans *= base;
        base *= base;
        b >>= 1;
    }
    return ans;
}

快速幂取模模板

int pow_mod(int a,int b,int c){
    int ans = 1;
    int base = a%c;
    while(b){
        if(b & 1) ans = (ans*base)%c;
        base = (base*base)%c;
        b >>= 1;
    }
    return ans;
}

B - Raising Modulo Numbers

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.

给定一些数,将这些书的次幂相加在modM,求结果

利用:(a + b) % p = (a % p + b % p) % p 在这里的a可以代表A^B次方

#include
#include
using namespace std;
typedef long long ll;
ll poww(ll x,ll y,ll mod)
{
	ll ans=1;
	while(y)
	{
		if(y&1) ans=ans*x%mod;     //快速幂取模
		x=x*x%mod;
		y>>=1;        //向右移位
	}
	return ans;
}

int main()
{
	int T;
	cin>>T;
	while(T--)
	{
		ll M,N,sum=0;
		cin>>M>>N;
		while(N--)
		{
			ll a,b;
			cin>>a>>b;
			sum=(sum+poww(a,b,M)%M)%M;     //利用给的公式进行计算
		}
		printf("%ld\n",sum);
	}
	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.

给你一个集合,找出其中和为偶数的子集,通过找规律可以得出遵循2^(n-1)-1,只需要计算式子的值即可。

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

ll poww(ll x,ll y,ll mod)
{
	ll ans=1;
	while(y)
	{
		if(y&1) ans=ans*x%mod;     //快速幂取模
		x=x*x%mod;
		y>>=1;        //向右移位
	}
	return ans;
}

int main()
{
	int T;
	cin>>T;
	while(T--)
	{
		int n;
		cin>>n;
		printf("%d\n",poww(2,n-1,1000000007)-1);
	}
	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.

题意就是领工资,不可以多领,多领是要输出多领的人的序号,没有则输出-1.

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

int main()
{
	int T;
	while(~scanf("%d",&T))
	{
		int a[10010];
		memset(a,0,sizeof a);       //每一次循环需要初始化数组
		for(int i=1;i<=T;i++)
		{
			int x;
			scanf("%d",&x);
			a[x]++;             //输入的数代表一个人零的工资的次数
		}	
		int flag=0;
		for(int i=1;i<=10000;i++)
		{
			if(a[i]>T-a[i])       //如果一个人领的工资的次数比所有人领工资的次数的一半要大,受惩罚
			{
				flag=i;            //flag变量来控制 i
				break;
			}
		}
		if(flag) printf("%d\n",flag);
		else printf("-1\n");
	}
	return 0;
}

E - Rightmost Digit

Given a positive integer N, you should output the most right digit of N^N.
题意是输出N^N数的最后一位
快速幂取模

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

ll poww(ll x,ll y)
{
	ll ans=1;
	while(y)
	{
		if(y&1) ans=ans*x%10;
		x=x*x%10;
		y>>=1;
	}
	return ans;
}

int main()
{
	int T;
	cin>>T;
	while(T--)
	{
		ll N;
		cin>>N;
		printf("%lld\n",poww(N,N));
	 } 
	 return 0;
}

F - 人见人爱A^B

求A^B的最后三位数表示的整数。
说明:A^B的含义是“A的B次方”
跟E题一样,只需要对1000取模即可

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

ll poww(ll x,ll y)
{
	ll ans=1;
	while(y)
	{
		if(y&1) ans=ans*x%1000;
		x=x*x%1000;
		y>>=1;
	}
	return ans;
}

int main()
{
	int A,B;
	while(~scanf("%d %d",&A,&B))
	{
		if(A==0 && B==0) break;
		printf("%d\n",poww(A,B));
	}
	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.
题意是给一个数,判断这个数对应的阶乘的最小值,这个数代表的是末尾0的个数
一个数的阶乘末尾0的个数与该数还有的5 的个数有关,5!=120,末尾1个0,10!的阶乘有两个。
所以只需要计算数中5的个数,再利用二分进行划分范围

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

ll check(ll x)
{
	ll ans=0;
	while(x)         //while循环计算5的个数
	{
		ans += x/5; 
		x=x/5;
	}
	return ans;
}

int main()
{
	int T,N=1;
	scanf("%d",&T);
	while(T--)
	{
		ll Q;
		scanf("%lld",&Q);
		ll l=0,r=1e10+10,mid,best=0;
		while(l=Q)
			{
				best=mid;
				r=mid;        //这里不能排除mid这个值,所以需要r=mid进一步缩小范围
			}
			else 
			{
				l=mid+1;
			}
		}
		printf("Case %ld: ",N++);
		if(check(best)==Q) printf("%lld\n",best);
		else printf("impossible\n");
	} 
	return 0;
 } 

输入,输出数据最好还是使用scanf和printf,省时间

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.

分蛋糕,每个人需要一样多,当然,不要忘记还有本人!!!
边界:
最小边界为0(每个人都不分蛋糕)
最大边界是每个人都有蛋糕(总体积 / 总人数)
之后使用二分法进行筛选

#include
#include
#define pi acos(-1)
using namespace std;
double pre[10010];

int main()
{
	int T;
	scanf("%d",&T);
	while(T--)
	{
		int N,F,x;
		double temp;
		scanf("%d %d",&N,&F);
		for(int i=1;i<=N;i++)
		{
			scanf("%d",&x);
			pre[i]=x*x*pi;      //pre数组用来存放蛋糕的体积
			temp+=pre[i];
		}	
		int cnt;
		double l=0,r=temp/(F+1),mid;
		while(r-l>0.000001)
		{
			cnt=0;
			mid = (l+r)/2;
			for(int i=1;i<=N;i++)
				cnt=cnt+(int)(pre[i]/mid);
			if(cnt>=(F+1))
			{
				l=mid;
			}
			else 
				r=mid;      //这里是实数,如果写成mid-1 的话,可能会错过点
		}
		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.
找出一个实数,满足上面式子成立,这个实数要求在0~100之间
范围已经给出了,直接利用二分法即可

#include
#include
#include
using namespace std;

double F(double x)
{
	return 8*x*x*x*x+7*x*x*x+2*x*x+3*x+6;
}

int main()
{
	int T;
	scanf("%d",&T);
	while(T--)
	{
		double Y;
		scanf("%lf",&Y);
		if(Y<6 || Y>807020306)     也可以写成YF(100)
		{
			printf("No solution!\n");
			continue;
		}
		else
		{
			double r=100,l=0,mid;
			while(fabs(F(mid)-Y)>0.000001)
			{
				mid = (l+r)/2.0;
				if(F(mid)>Y)
				{
					r=mid;
				}
				else if(F(mid)

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.

找出和大于S的最短子序列的长度,可以使用尺取法
尺取相当于就是双指针,l和r两个指针,r指针先移动,如果两个指针之间值的和大于S的话,移动 l 指针,每移动一次记录一次,再用min函数得出最小值,输出这个最小值即可。

#include
#include
#include
using namespace std;

int main()
{
	int T,a[100010];
	scanf("%d",&T);
	while(T--)
	{
		int N,S;
		memset(a,0,sizeof(a));
		scanf("%d %d",&N,&S);
		for(int i=1;i<=N;i++)
		{
			scanf("%d",&a[i]);	
		}
		int l=1,r=1,sum=0,ans=1e9;      
		while(l<=N)
		{
			while(r<=N && sum=S) ans=min(ans,r-l);
			sum -= a[l];
			l++;
		}
		if(ans==1e9) printf("0\n");
		else printf("%d\n",ans);
	}
	return 0;
 } 

尺取的模板

int l=1,r=1,sum=0,ans=1e9;   //ans这个数值尽量取大 
while(l<=N)
	{
		while(r<=N && sum=S) ans=min(ans,r-l);    //每一次取最小值 
		sum -= a[l];   //移动l指针,每一栋一次,减去l指针对应的前一个值 
		l++;     //l指针移动 
	}

你可能感兴趣的:(第二次公开课(快速幂,二分))