待处理的奇怪的算法

  1. 计算n的阶乘结果末尾有几个零
int findzero(int x)
{
       int ans=0;
       while(n>=4)	//while(ans)
       {
              ans+=n/5;
              n/=5;
       }
       return ans;

}
  1. 组合数与杨辉三角
    (1)组合恒等式:C(n,m)=C(n-1,m-1)+C(n-1,m)
    (2)杨辉三角形的第i行第j列就是c(i-1,j-1)
    (3)c[0][0]=c[1][0]=c[1][1]=1;
    (4)求c(m,n):
long long c[105][105];
const int mod = 1000000007;
void init()
{
    c[0][0]=1;
    for(int i=1;i<=100;i++){
        c[i][0]=1;
        for(int j=1;j<=100;j++){
            c[i][j] = (c[i-1][j-1]+c[i-1][j])%mod;
        }
    } 
}
  1. 欧拉函数
    (1)质因数分解法
int oula[100010];
ll Oular(ll n)	
{
	ll ans=n;
	for(int i=2;i*i<=n;i++)
	{
		if(n%i==0)
		{
			ans=ans*i/i-1;
			while(n%i==0)
				n/=i;
		} 
	}
	if(n!=1)
		ans=ans*n/n-1;
	return ans;
}

(2)线性打表法

const int n=100010;
int oula[n];
void Oula()		
{
	for(int i=0;i<n;i++)
		oula[i]=i;
	for(int i=2;i<n;i++)
	{
		if(oula[i]==i)
		{
			for(int j=i;j<n;j+=i)
				oula[j]=oula[j]/i*(i-1);
		}
	}
}
  1. 求n的阶乘的位数
    (1)斯特林公式(求n!的近似值):(根号下2PIn)*((n/e)的n次方)
    对等号两边同时取以10为底的对数,求出来的位数少一位,例如log10(10)=1,但10是两位数。

斯特林数判断阶乘位数

#include<stdio.h>
#include<math.h>
using namespace std;
#define pi 3.14159265
#define e 2.71828182 
int main()
{
    int n, digit;
    scanf ("%d", &n);
    digit= (int) ((0.5 * log (2 * pi * n) + n * log (n) - n * log(e) / log (10));
    printf ("%d\n", digit + 1);
    return 0;
}
//斯特林数判断阶乘位数
(2)直接log10
任意一个正整数a的位数
等于(int)log10(a) + 1;为什么呢?下面给大家推导一下:

  对于任意一个给定的正整数a,
  假设10^(x-1)<=a<10^x,那么显然a的位数为x位,
  又因为
  log10(10^(x-1))<=log10(a)<(log10(10^x))
  即x-1<=log10(a)<x
  则(int)log10(a)=x-1,
  即(int)log10(a)+1=x
  即a的位数是(int)log10(a)+1

我们知道了一个正整数a的位数等于(int)log10(a) + 1,
现在来求n的阶乘的位数:
假设A=n!=1*2*3*......*n,那么我们要求的就是
(int)log10(A)+1,而:
	log10(A)
        =log10(1*2*3*......n)  (根据log10(a*b) = log10(a) + log10(b)有)
         =log10(1)+log10(2)+log10(3)+......+log10(n)
现在我们终于找到方法,问题解决了,我们将求n的阶乘的位
数分解成了求n个数对10取对数的和,并且对于其中任意一个数,
都在正常的数字范围之类。

总结一下:n的阶乘的位数等于
		  (int)(log10(1)+log10(2)+log10(3)+......+log10(n)) + 1


5. 二进制枚举
//斯特林数判断阶乘位数
  int n;
    cin >> n;
    for(int i = 0; i < (1<<n); i++) //遍历从0~2^n-1个状态,1取0不取
    {
        for(int j = 0; j < n; j++) //遍历二进制的每一位
        {
            if(i & (1 << j))
//1<<j输出一个n位中只有一位(第j位)为1的二进制数字,与i进行与运算,同1则为1来判断该位是否为1 
//判断二进制第j位是否存在
            {
                printf("%d ",j);//如果存在输出第j个元素
            }
        }
        printf("\n");
    }

typedef struct node
{
    int pi;
    int di;
    friend bool operator < (struct node a,struct node b)
    {
            return a.pi > b.pi;//按pi的值由小到大排序
    }
}stone;

结构体变量是不能使用 < 比较的,必须重载
与sort不同,return a<b,返回的是一个递减的而不是递增的,因为优先队列中是要进行排序的,如果a小于b,返回一个真值,交换位置

  1. 洛谷 P2241 统计方形
    (1)矩形数量 = 正方形数量 + 长方形数量
    (2)对于矩形来说,固定右下角(i , j),那么矩形数量为 i * j。
    链接:https://blog.youkuaiyun.com/qq_45260619/article/details/115342478?utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromBaidu%7Edefault-6.no_search_link&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromBaidu%7Edefault-6.no_search_link

  2. 一个减少时间复杂度的巧妙方法
    例如:有数组A[N],B[N],统计有多少对 (i,j) 整数满足 Ai=Bj?
    解1(时间复杂度(n^2)):
    解2(时间复杂度(n)):

long long ans=0;
vector<int> C(n;	//由于n是可变的,所以这里设置动态数组,vector会自动给数组赋值0,所以不需要初始化
for(int j=0;j<N;j++)
        C[B[j]]+=1;
for(int i=0;i<N;i++)
        ans+=C[A[i]];
  1. N的立方和
    1的3次方+2的3次方+3的3次方+4的3次方+…+n的3次方
    =(1+2+3+4+…+n)²
    =[n*(n+1)/2]²
    =(1/4)(n+1)²

  2. 排列组合
    (1)Amn(m上标,n下标)=n*(n-1)(n-2)(n-3)…(n-m+1),例如A58=87654(最后一项为8-5+1)
    (2)Cmn(m上标,n下标)=[n
    (n-1)(n-2)(n-3)…(n-m+1]/123…m,例如C58=87654(最后一项为8-5+1)/12345(最后一项为m=5)。

  3. 判断一个函数成立的解
    例如:求方程 a1x1−a2x2+a3x3−a4x4+a5x5−a6x6=0在 xi∈[1,k]内有多少组正整数解。
    把式子转换一下
    a1x1+a3x3+a5x5=a2x2+a4x4+a6x6
    先预处理左边的,枚举左边的,用map记录答案出现的次数
    再枚举右边,累加答案出现的次数

#include <bits/stdc++.h>
using namespace std;
int k,a1,a2,a3,a4,a5,a6;
map<int,int> v;
int main()
{
	cin>>k>>a1>>a2>>a3>>a4>>a5>>a6;
	for(int i=1;i<=k;i++)
		for(int j=1;j<=k;j++)
			for(int m=1;m<=k;m++)
			{
				int ans=a1*i+a3*j+a5*m;
				v[ans]++; 
			}
	int sum=0;
	for(int i=1;i<=k;i++)
		for(int j=1;j<=k;j++)
			for(int m=1;m<=k;m++)
			{
				int ans=a2*i+a4*j+a6*m;
				sum+=v[ans];
			}
	cout<<sum<<endl;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值