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;

浙公网安备 33010602011771号