筛质数
虽然是基础课,但是不是简单的意思,从难度来看,提高课也难不了多少,提高课主要讲应用。
夏洛特和他的女朋友
错误原因题目没有看懂,不明白下面这句话
一件珠宝的价格是另一件珠宝的价格的质因子时,两件珠宝的颜色不同。 以为 2 ,4 , 6, 8......等需要四个颜色
其实很简单,就是给所有质数染成一,合数染成二,特判下n等于多少时,染料的个数才大于1.
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5+5;
int prime[N];//只是临时存一下
bool vis[N];// 最终主函数查看这个是否为素数
void get_prime() {
memset(vis,true,sizeof vis);
memset(prime,0,sizeof prime);
vis[0] = vis[1] = false;
for(int i = 2; i <= N; ++i)
{
if (vis[i]) {
prime[++prime[0]] = i;//prime[0]相当于全局变量定义一个K
}
for(int j = 1;j <= prime[0] && i * prime[j] <= N; ++j) {
vis[i * prime[j]] = false;
if (i % prime[j] == 0) //避免重复筛选 // 如果等于零 primes[i] 一定是i的最小质因子,则p 一定是p *i 的最小质因子,如果不等于零,p 一定小于i的所有质因子
break;
}
}
}
int main()
{
int n ;
get_prime() ;
cin >> n;
int m = 0 ;
if( n <= 2) m = 1 ;
else m = 2;
cout << m << endl;
for( int i= 1 ; i <= n ; i++)
{
if(vis[i+1])
cout << 1<<" ";
else cout << 2 << " ";
}
return 0;
}
质数距离
题目数据范围比较大,注意筛发是筛1 - n ,不能筛某个区间[ l , r];但是题目中说其中 L 和 U 的差值不会超过 1e6。
这里有一个核心的性质就是:任何一个合数n,一定存在一个质因子,小于等于根号n
因此可以把1 -根号 2^31-1的质数给筛出来

这个就很小了 ,大小也就是四万到五万之间,所以就是把1 到 五万之间的质数都筛出来,那么此时U到L之间的合数都存在1 到 五万之间的质因子。把这些质数的倍数(U到L之间)全部筛掉,剩下来的就是质数。
补充:j应该等于 大于等于L的最小的一个P的倍数 ,那么这个数应该咋找到呢?

注意图片里是上取整,也给出了如何下取整、。
#include <bits/stdc++.h>
using namespace std;
const int N = 1e6 + 10 , M = 5e4 + 10;
int primes[M] , cnt;
bool st[N];
void get_primes(int n)
{
memset( st , false , sizeof st);
cnt = 0;
for( int i = 2 ; i <= n ; i++)
{
if(!st[i]) primes[cnt++] = i;
for( int j = 0 ; primes[j] * i <= n ; j++)
{
st[primes[j] * i] = true;
if( i % primes[j] == 0) break;
}
}
}
int main()
{
long long l ,r ;
while(cin >> l >> r)
{
get_primes(50000);
memset( st , false , sizeof st);//清空一下 , 因为刚才的事就用过了
for( int i = 0 ; i < cnt ; i++)
{
int p = primes[i];
// 把【L,R】中的所有P的倍数筛掉
for( long long j = max((l + p -1) / p * p , 2ll * p); j <= r ; j += p ) //j应该等于 大于等于L的最小的一个P的倍数
{//因为(l + p - 1)/p可能等于p,然后错误地标记st[i] = true,这样就把一个质数p错误地标记成了合数,所以至少要从2*p开始
st[j -l] = true;//注意偏移量
}
}
cnt = 0 ;
for( int i = 0 ; i <= r - l; i++)
{
if( !st[i]&& i + l > 1)
primes[cnt++] = i + l;
}
if( cnt < 2 ) puts("There are no adjacent primes.");
else
{
int mins = 0 ,maxp = 0 ;
for( int i = 0 ; i + 1 < cnt ; i++)
{
int d = primes[i +1] - primes[i];
if( d < primes[mins + 1] - primes[mins]) mins = i;
if( d > primes[maxp + 1] - primes[maxp]) maxp = i;
}
printf("%d,%d are closest, %d,%d are most distant.\n" , primes[mins] , primes[mins + 1] , primes[maxp] , primes[maxp + 1]);
}
}
return 0;
}
阶乘分解
阶乘分解
精简代码
#include <bits/stdc++.h>
using namespace std;
const int N = 1e6 + 10;
int primes[N] , cnt;
bool st[N];
void init( int n)//简单线性筛发
{
for( int i = 2 ; i <= n ; i++)
{
if(!st[i]) primes[cnt++] = i;
for( int j = 0 ; primes[j] * i <= n ; j++)
{
st[i * primes[j]] = true;
if( i % primes[j] == 0) break;
}
}
}
int main()
{
int n ;
cin >> n ;
init( n );
for( int i = 0 ; i < cnt ; i++)
{
int p = primes[i];
int s = 0 ;
for( int j = n ; j ; j /= p) s += j / p;
cout << p << " " << s << endl;
}
return 0;
}
快速幂
序列的第K个数
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int mod = 200907;
int qmi(int a, int k)
{
int res = 1;
while (k)
{
if (k & 1)
res = (LL)res * a % mod;
a = (LL)a * a % mod;
k >>= 1;
}
return res;
}
int main()
{
int n;
cin >> n;
while (n--)
{
int a, b, c, k;
cin >> a >> b >> c >> k;
if (a + c == b * 2)
cout << (a + (b - a) * (LL)(k - 1)) % mod << endl;
else
cout << (LL)a * qmi(b / a, k - 1) % mod << endl;
}
system("pause");
return 0;
}
越狱
对于这题真是无语了,想了半天,感觉还是很模糊。看了答案也是略懂非懂的。
考虑 n 个犯人,m种宗教,如何安排不会导致犯罪。第一个位置可以有 m个选择,则与第一个相邻的第二个位置就只有 m−1中选择。考虑第 i个位置,则为了不和他左侧的 i−1 位置发生冲突,一共有 m−1
种选择。因此不会导致犯罪的方案是: m⋅(m−1)^n−1
则会导致犯罪的方案是:m^n−m⋅(m−1)^n−1
但是本题可能有个很大的坑,就是最后答案可能是负数。
你好,我问一下 这里答案加mod再取余是防止取模结果为负数,可前面一项一定比后面一项大啊,不可能是负数啊。为啥要加一个mod呢?
例如模数是 10,那么 11 - 8 取模以后就是 1 - 8 是负数
#include <bits/stdc++.h>
using namespace std;