【数论】

T一:14682约数个数和

题目要求:给个n求1到其的所有约数个数之和。n <= 100000000       2^24<n<2^32使用数组明显不现实

百度了下思路 :枚举约数,判断他是谁的约数,并记录一共(即他的倍数有多少个),从1到n,sum+=n/i记录

如3约数共是5=3(是1倍数的有三个!!因为数类叠加厉害)+1+1;

#include<iostream>
using namespace std;
int main()
{
	int n,sum=0;
	cin>>n;
	for(int i=1;i<=n;i++)
	{
		sum+=n/i;
	}
	cout<<sum<<endl;
	return 0;
}

T2:最大字段和问题-动态规划

#include <stdio.h>
#include <iostream>
#include <string.h>
using namespace std;
int s[10000055];
//简单dp 
int main(){
  int ans=0,b=0,maxn=0;
  int n;
  cin>>n;
  
  for(int i=1;i<=n;i++)
  {
    scanf("%d",&s[i]);//数据量大使用scanf优化 
    if(i==1)
	  maxn=s[i];//初始给max赋值 
	  //开始找最大子序列,只要他的值叠起来不等于0,就可以计算进去 
    if(ans>0)
      ans+=s[i]; 
    else
      ans=s[i];//叠到这个的时候,前面的最大值已找到记录在maxn里,现在削减到0,且从现在0为ans新起点叠代 
    maxn=ans>maxn?ans:maxn; //每叠一次判断一次 
  }
  cout<<maxn;//最后输出最大子段 
}

哈尔滨工程大学ACM预热赛C king


第一天可以产a吨粮食,第二天会变成前一天的a倍,以此类推。
n天后大臣准备把这些粮食尽可能多的平均分给b个城池
为了方便,每个城池分到的粮食都是整吨整吨哒!
剩下的粮食国王准备贪污,国王能贪到多少吨粮食呢?

由于数据量过大,直接算会爆炸,应该使用快速幂

#include<bits/stdc++.h>
using namespace std;
int main()
{
    long long int t;
    cin>>t;
    while(t--)
    {
        long long int a,n,b,ans=1;
        cin>>a>>n>>b;
        while(n)
        {
            if(n&1)//存在不为0
            ans=(ans*a)%b;//ans乘进去

            a=(a*a)%b;//二进制位自增
            n>>1;//n/=2改良版
        }
        cout<<ans<<endl;
    }
}

关于快速幂

基于数学里底数的指数相加等于同底数指数相乘

扫描二维码关注公众号,回复: 10145579 查看本文章

 假设我们要求a^b,那么其实b是可以拆成二进制的,该二进制数第i位的权为2^(i-1),例如当b==11时

                             a11=a(2^0+2^1+2^3)

  11的二进制是1011,11 = 2³×1 + 2²×0 + 2¹×1 + 2º×1,因此,我们将a¹¹转化为算 a2^0*a2^1*a2^3,

 1 int poww(int a, int b) {
 2     int ans = 1, base = a;
 3     while (b != 0) {
 4         if (b & 1 != 0)
 5             ans *= base;
 6             base *= base;
 7             b >>= 1;
 8     }
 9     return ans;
10 }

怎么说呢,能用位运算就用位运算,位运算是最快的

一下是老狗的:https://www.acwing.com/solution/AcWing/content/1290/挺详细的

快速幂) O(logb)O(logb)

对于算法的理解还不够深刻,难免有所疏漏,还请大佬不吝赐教

时间复杂度分析:每次对b进行右移操作

感谢评论大佬分享
(a * b ) % p = ((a % p ) * (b % p) ) % p ;
(a + b ) % p = ((a % p ) + (b % p) ) % p ;
证明仅以a * b % p;
a = c1 * p + yu1 ; 
b = c2 * p + yu2;
(a * b) % p = (c1 * p + yu1 ) * (c2 * p+ yu2 ) % p = (yu1*yu2)%p;

本题逻辑核心!!
说明:以下a(n)为a^(2^n)
    1.对于(a^b)%p式子的展开
        a^b=1*a(x1)*a(x2)*a(x3).....
        a^b%p=( (1*a(x1)*a(x2)%p) * (a(x3)%p) ) %p
        1*a(x1)*a(x2)%p = ( (1*a(x1)%p) * (a(x2)%p) )%p
        1*a(x1)%p = ( (1%p) * (a(x1)%p) )%p
        所以res初始化值为1%p
        算法即是从下向上实现 
    2.理解a = a *a % p
        迭代a: ( res * (a(xn)%p) )%p 其中的a(xn)%p = a(xn-1)*a(xn-1)%p

湘潭:ICPC比赛中,谁通过的题数多,谁排名靠前;在通过题数相同的情况下,谁的罚时少,谁排名靠前;如果前两者都相同,就看最后正确提交的时间,谁早最排名靠前。 现在给你两个队伍的正确通过的题数、罚时和最后正确提交时间,请判断一下,谁的排名更靠前?

#include<iostream>
using namespace std;
int main()
{
	int a[7],flag=0,k=1;
	for(int i=0;i<6;i++)
		cin>>a[i];
	for(int j=0;j<3;j++)
	{
		if(a[j]==a[j+3])
			flag=1;
		else
			{
				if(k==1)
					a[j]>a[j+3]?flag=2:flag=3;
				else
					a[j]<a[j+3]?flag=2:flag=3;
			}
//		switch(flag)
//		{
//			case 1:continue;
//			case 2:cout<<"1"<<endl;break;
//			case 3:cout<<"2"<<endl; break;
//		}
		if(flag==2)
		{
			cout<<"1"<<endl;
			break;
		}
		if(flag==3)
		{
			cout<<"2"<<endl;
			break;
		}
		k=2;
	}
	if(flag==1)
	cout<<"God"<<endl;
				
	
	return 0;
	
}

 

发布了27 篇原创文章 · 获赞 5 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/qq_38304672/article/details/89366977