ACM细小技巧

本篇主要记一些细小的技巧

1.欧拉筛
2.阶乘分解
3.快速幂
4.快速乘
5.离散化
6.除法取模

欧拉筛

通过最小质因数来筛掉合数

//maxn为最大范围
int prime[maxn];//prime[i]表示第i个素数
int visit[maxn];//标记是否是素数
void Prime(){
    memset(prime,0,sizeof(prime));
    memset(visit,0,sizeof(visit));
    for (int i = 2;i <= maxn; i++) {
        if (!visit[i])
            prime[++prime[0]] = i;      //纪录素数, 这个prime[0]用来计一直素数数量
        for (int j = 1; j <=prime[0] && i*prime[j] <= maxn; j++) {
            visit[i*prime[j]] = 1;      //prime[j]即为i*prime[j]的最小质因数
            if (i % prime[j] == 0) {    //如果能整除,表示i*prime[j]的最小质因数为prime[j],但i*prime[j+1]的最小质因数也为prime[j],后面会自然排除,所以直接跳出;
                break;
            }
        }
    }
}

阶乘分解

我也没搞清楚原理,但大概能知道怎么回事,就很迷

void fen(int n)    //分解n的阶乘,prime[i]表示第i个素数,num[i]表示分解后第i个素数的个数
{
	for (int i = 2; prime[i] < n; i++)
	{
		int x = n;
		num[i] += x / prime[i];
		x -= x / prime[i];
	}
}

快速幂

就是通过二进制来加速,不得不说二进制牛逼

int kpow(int a, int b)//求a的b次方
{
	int ans = 1;//初始值
	int num = a;//a的一次方,num就是权值
	while (b)   //二进制每一位计算
	{
		if (b % 2 == 1)ans *= num;//如果二进制这位数是1,ans就得乘这个权值
		num *= num;               //权值进一位
		b = b >> 1;               //下一位
	}
	return ans;
}

快速乘

算a*b,同样使用二进制

long long ksc(long long a, long long b){
      long long ans=0;
      long long t=a;
      while(b){
            if(b%2==1)ans += t;
            t*=2;
            b>>=1;
      }
      return ans;
}

离散化

可以把分散的数聚集起来,只关心他们之间的大小关系
ans为需离散化的数组,arr数组元素和ans相同

sort(arr,arr+n);   //排序,n为数组个数
n=unique(arr,arr+n);   //去重,把重复的放在后面,此时n就是不重复个数
for(int i=0;i<n;i++){
    ans[i]=lower_bound(arr,arr+n,ans[i])-arr;//取得位置,即我们得到位置关系
}

除法取模

求( a / b ) % p,我们可以把除法变为乘法( a / b ) % p = ( a % p ) * ( ( 1 / b ) % p ),首先知道费马小定理:若x与y互质,则\(x^{y-1}\equiv1\) ( % y );
\(x*x^{y-2}\equiv 1\)( % y )-->\(x^{y-2}\equiv 1/x\)( % y );
所以a / b % p = a * \(b^{p-2}\) % p;

就先这些了,以后想起什么再写好了

posted @ 2020-03-24 21:01  我是小怪兽  阅读(101)  评论(0)    收藏  举报