zoukankan      html  css  js  c++  java
  • 寒假练习 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;
    }
    

      

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

  • 相关阅读:
    进程与线程的一个简单解释
    如何更优雅的写出你的SQL语句
    SQL 性能优化梳理
    如何写出让同事无法维护的代码?
    Linux配置IP常用命令
    Linux中防火墙命令笔记
    蓝牙技术的工作原理及用途
    别死写代码,这 25 条比涨工资都重要
    搞清这些陷阱,NULL和三值逻辑再也不会作妖
    计算机网络:TCP和UDP的对比
  • 原文地址:https://www.cnblogs.com/Ivy-End/p/4290080.html
Copyright © 2011-2022 走看看