寒假练习 06

这一次主要是数论专题,感到思维量比上一次的数学题要多多了。同样的问题也是英文题看起来有些吃力。

 

UVaOJ 575

这应该算不上是一个数论题,它重新定义了一种进制转换的公式,然后根据公式计算即可。

#include <iostream>

using namespace std;

int Pow(int x, int y);

int main()
{
	string x;
	while(cin >> x)
	{
		if(x == "0") { break; }
		int ans = 0;
		for(int i = 0; i < x.length(); i++)
		{ ans += (x[i] - '0') * (Pow(2, x.length() - i) - 1); }
		cout << ans << endl;
	}
	return 0;
} 

int Pow(int x, int y)
{
	int ret = 1;
	for(int i = 1; i <= y; i++)
	{ ret *= x; }
	return ret;
}

  

UVaOJ 10110

这是一道典型的数论题,最后亮着的灯,它的开关一定被拨动了奇数次。所以,我们只要看它的因数个数的奇偶性。

记得高中数学竞赛的时候遇到过类似的题目,有一个结论——完全平方数的因数有奇数个,非完全平方数的因数有偶数个。

这个命题的证明有些繁琐,读者自己思考一下就会发现,这个结论是正确的。

#include <iostream>
#include <math.h>

using namespace std;

int main()
{
	long long N;
	while(cin >> N)
	{
		if(N == 0) { break; }
		long long x = (long long)floor(sqrt(N * 1.0) + 0.5);
		if(x * x == N) { cout << "yes" << endl; }
		else { cout << "no" << endl; }
	}
	return 0;
}

  

UVaOJ 550

类似倒推的思想。

首先,我们有B, D, M——分别代表进制、最后一位数字、乘数。我们不妨记满足条件的数字为N,且N * M = S。

有了上述假设,我们就可以进行如下操作:

N的最后一位数字为D,那么S的最后一位数字记为T = (D * M) % B(这里为B进制)。

这时候需要注意的是,S的最后一位数字,恰好是N的倒数第二位数字,那么也就是说N的倒数第二位数字为T。

有了N的倒数第二位数字,我们就可以求出S的倒数第二位数字为(T * M) % B + T / B(其中T / B为进位),以此类推。

直到我们计算出来的数字与一开始给定的数字D相当,这时候的N的位数即为答案。

#include <iostream>

using namespace std;

int main()
{
	int B, D, M;
	while(cin >> B >> D >> M)
	{
		int nCnt = 1;
		int nD = D;
		while((nD = M * (nD % B) + (nD / B)) && nD != D)
		{ nCnt++; }
		cout << nCnt << endl;
	}
	return 0;
} 

  

UVaOJ 568

由于数据范围比较小,我们可以直接算出来,记得在每次计算的时候把末尾的0去掉,同时为了防止溢出,我们可以对10的一个幂次取模。

这里选择了10000,因为最大的N为10000。但是这个选取并不是任意的,比如我们取10,计算出来的结果就会出错。

#include <iostream>
#include <iomanip>

using namespace std;

const int MAX = 100000;

int main()
{
	int N;
	while(cin >> N)
	{
		int ans = 1;
		for(int i = 1; i <= N; i++)
		{
			ans *= i;
			while(ans % 10 == 0) { ans /= 10; }
			ans %= MAX;
		}
		cout << setw(5) << N << " -> " << ans % 10 << endl;
	}
}

  

UVaOJ 408

这道题目就是求满足seed(x + 1) = [seed(x) + STEP] % MOD的seed(x)能否组成模MOD的剩余系。

有一个结论,若gcd(STEP, MOD) = 1,则可以组成一个模MOD的剩余系。

我们可以这样来证明:

seed(x + 1) = [seed(x) + STEP] % MOD = [seed(x - 1) + 2 * STEP] % MOD = [seed(x - 2) + 3 * STEP] % MOD = ... = [seed(0) + (x + 1) * STEP] % MOD。

若不能满足条件,则必定存在0 <= i ≠ j < MOD 的整数i,j满足:seed(i) = seed(j),即[seed(0) + i * STEP] % MOD = [seed(0) +j * STEP] % MOD。

即((j - i) * STEP) % MOD = 0,又j - i < MOD,所以gcd(STEP, MOD) ≠ 1。

即STEP中含有MOD的因子——若MOD整除(j - i),那么STEP中含有MOD的因子(MOD / (j - i)),反之,STEP含有因子MOD。

故需满足题设条件,必有gcd(STEP, MOD) = 1。

证毕。

#include <iostream>
#include <iomanip>

using namespace std;

int gcd(int x, int y);

int main()
{
	int x, y;
	while(cin >> x >> y)
	{
		if(gcd(x, y) == 1) { cout << setw(10) << x << setw(10) << y << "    Good Choice" << endl; }
		else { cout << setw(10) << x << setw(10) << y << "    Bad Choice" << endl; }
		cout << endl;
	}
	return 0;
}

int gcd(int x, int y)
{
	if(y == 0) { return x; }
	else { return gcd(y, x % y); }
}

  

UVaOJ 350

简单模拟,没有想到数论的做法。不断的计算L,直到发现重复。

#include <iostream>
#include <memory.h>

using namespace std;

const int MAX = 10240;

int f[MAX];

int main()
{
	int nCase = 0;
	int Z, I, M, L;
	while(cin >> Z >> I >> M >> L)
	{
		if(Z == 0 && I == 0 && M == 0 && L == 0) { break; }
		int nCnt = -1;
		memset(f, 0, sizeof(f));
		do
		{
			L = ((Z % M) * (L % M) + (I % M)) % M;
			f[L]++;
			nCnt++;
		}
		while(f[L] == 1);
		cout << "Case " << ++nCase << ": " << nCnt << endl;
	}
 	return 0;
}

  

 UVaOJ 10061

要求N!转化为B进制后的位数以及末尾0的个数。

为了简化问题,我们首先来看10进制的情况。

我们知道,在10进制情况下,我们有f(N) = f(N / 5) + N / 5。

证明:令k = N / 5,则N! = 5k * 5(k - 1) * ... * 10 * 5 * a = 5^k * k! * a (其中a为不能被5整除的部分)

因此,f(N) = f(k) + k = f(N / 5) + N / 5。证毕。

有了上面的结论,我们可以大胆猜测,对于B进制数,我们有

f(N, B) = f(N / X, B) + N / X(其中X为B的最大因数),证略。

这样,我们就解决了第一个问题,对于第二个问题,我们可以直接去对数,计算log(N!),即log1 + log2 + log3 + ... + logN。

#include <iostream>
#include <math.h>

using namespace std;

const int MAX = 1 << 20;

double pLog[MAX];

int main()
{
	for(int i = 1; i < MAX; i++)
	{ pLog[i] = pLog[i - 1] + log(i); }
	int N, B;
	while(cin >> N >> B)
	{
		int nLen = (int)floor(pLog[N] / log(B) + 1E-9) + 1;
		int nMaxFactor, nFactorCnt = 0, nCnt = 0;
		for(int i = 2; i <= B; i++)
		{
			nFactorCnt = 0;
			while(B % i == 0)
			{
				nMaxFactor = i;
				nFactorCnt++;
				B /= i;
			}
		}
		while(N)
		{
			N /= nMaxFactor;
			nCnt += N;
		}
		cout << nCnt / nFactorCnt << " " << nLen << endl;
	}
	return 0;
}

  

UVaOJ 10392

质因数分解即可,要注意题目中说只有一个大于1,000,000的因子,但是还是需要处理本身就是素数以及除到最后不等于1的情况。

#include <iostream>
#include <memory.h>
#include <vector>

using namespace std;

const int MAX = 1000020;

vector<int> pVec;
bool pVisited[MAX];

int main()
{
	memset(pVisited, false, sizeof(pVisited));
	for(int i = 2; i < MAX; i++)
	{
		if(!pVisited[i]) { pVec.push_back(i); }
		for(int j = i + i; j < MAX; j += i)
		{ pVisited[j] = true; }
	}
	
	long long N;
	while(cin >> N)
	{
		if(N < 0) { break; }
		int nCnt = 0;
		for(int i = 0; i < pVec.size(); i++)
		{
			if(N < pVec[i]) { break; }
			while(N % pVec[i] == 0)
			{
				cout << "    " << pVec[i] << endl;
				N /= pVec[i];
				nCnt++;
			}
		}
		if(nCnt == 0 || N != 1) { cout << "    " << N << endl; }
		cout << endl;
	}
	return 0;
}

  

UVaOJ 10879

这道题目的样例好像有点吓唬人,其实里面应该有spj的。

数据量不大,直接分解因式即可。

#include <iostream>

using namespace std;

int main()
{
	int T, N;
	cin >> T;
	for(int i = 1; i <= T; i++)
	{
		cin >> N;
		cout << "Case #" << i << ": " << N;
		int nCnt = 0;
		for(int j = 2; j * j <= N; j++)
		{
			if(N % j == 0)
			{
				cout << " = " << j << " * " << N / j;
				nCnt++;
			}
			if(nCnt == 2) { break; }
		}
		cout << endl;
	}
	return 0;
}

  

数论专题很多都是看着题解做的,因为很多都不知道,学到了很多新的东西。

posted @ 2015-02-13 12:50  Ivy_End  阅读(311)  评论(0编辑  收藏  举报