2020.2.14 大一寒假训练九(素数筛)

Problem A:NEFU586 纯素数

每一位单独处理出来

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e6+1;
int cnt=0, max1=1e6, prime[maxn];
bool flag[maxn];
void init()
{
    fill(flag, flag+maxn, 1);
    flag[0]=0;
    flag[1]=0;
    for(int i=2; i<=max1; i++)
    {
        if(flag[i])
        {
            prime[++cnt] = i;
        }
        for(int j=1; j<=cnt&&prime[j]*i<=max1; j++)
        {
            flag[prime[j]*i] = 0;
            if(!(i%prime[j])) break;
        }
    }
}
bool judge(int k)
{
    int wei[7], len=0;
    fill(wei, wei+7, 0);
    while(k)
    {
        wei[len++] = k%10;
        k /= 10;
    }
    for(int i=0; i<len; i++)
    {
        int tmp=0;
        for(int j=i; j>=0; j--) tmp = tmp*10+wei[j];
        if(!flag[tmp]) return 0;
    }
    return 1;
}
int main()
{
    ios::sync_with_stdio(false);
    int n;
    init();
    while(~scanf("%d", &n))
    {
        if(judge(n)) printf("YES\n");
        else printf("NO\n");
    }
    return 0;
}

Problem B:NEFU587 半素数

当i是n的因子时,可同时判断n/i。

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e7+1;
int cnt=0, max1=1e7, prime[maxn];
bool flag[maxn];
void init()
{
    fill(flag, flag+maxn, 1);
    flag[0]=0;
    flag[1]=0;
    for(int i=2; i<=max1; i++)
    {
        if(flag[i])
            prime[++cnt] = i;
        for(int j=1; j<=cnt&&prime[j]*i<=max1; j++)
        {
            flag[prime[j]*i] = 0;
            if(!(i%prime[j])) break;
        }
    }
}
bool judge(int k)
{
    for(int i=2; i*i<=k; i++)
        if(!(k%i) && flag[i] && flag[k/i]) return true;
    return false;
}
int main()
{
    init();
    int n;
    while(~scanf("%d", &n))
    {
        if(judge(n)) printf("YES\n");
        else printf("NO\n");
    }
    return 0;
}

Problem C:NEFU825 函数版素数判定

此题使用cin,cout会超时(反正我是)。

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e7+1;
int cnt=0, max1=1e7, prime[maxn];
bool flag[maxn];
void init()
{
    fill(flag, flag+maxn, 1);
    flag[0]=0;
    flag[1]=0;
    for(int i=2; i<=max1; i++)
    {
        if(flag[i])
            prime[++cnt] = i;
        for(int j=1; j<=cnt&&prime[j]*i<=max1; j++)
        {
            flag[prime[j]*i] = 0;
            if(!(i%prime[j])) break;
        }
    }
}
bool judge(int n)
{
    bool flag = 1;
    for(int i=1; prime[i]<=sqrt(n); i++)
        if(n%prime[i]==0)
        {
            flag = 0;
            break;
        }
    if(n==1) flag=0;
    return flag;
}
int main()
{
    //ios::sync_with_stdio(false);
    int n;
    init();
    while(~scanf("%d", &n))
    {
        if(judge(n)) printf("YES\n");
        else printf("NO\n");
    }
    return 0;
}

Problem D:NEFU585 最大素因子

与模板相比可额外申请一个数组用来存该数的下标(与prime正好相反)。

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e6+1;
int cnt=0, max1=1e6, prime[maxn], reprime[maxn];
bool flag[maxn];
void init()
{
    fill(flag, flag+maxn, 1);
    flag[0]=0;
    flag[1]=0;
    for(int i=2; i<=max1; i++)
    {
        if(flag[i])
        {
            cnt++;
            prime[cnt] = i;
            //cout<<cnt<<endl;
            //return;
            reprime[i] = cnt;
            //cout<<cnt<<" "<<i<<endl;
        }
        for(int j=1; j<=cnt&&prime[j]*i<=max1; j++)
        {
            flag[prime[j]*i] = 0;
            if(!(i%prime[j])) break;
        }
    }
}
int query(int k)
{
    if(k==1) return 0;
    if(k==2) return 1;
    //cout<<flag[5]<<" "<<prime[5]<<" "<<reprime[5]<<endl;
    for(int i=k; i>=2; i--)
        if(k%i==0 && flag[i])
        {
            //cout<<"i"<<i<<endl;
            return reprime[i];
        }
}
int main()
{
    ios::sync_with_stdio(false);
    int n;
    init();
    while(cin>>n)
    {
        cout<<query(n)<<endl;
    }
    //cout<<flag[max1]<<endl;
    return 0;
}

Problem E:NEFU781 素数与数论

存储下标方式与D题相同,此时不能直接使用x和y进行reprime[x]reprime[y]的操作,而应先是x和y自增或自减至区间内首尾素数。

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e6+1;
int cnt=0, max1=1e6, prime[maxn], reprime[maxn];
bool flag[maxn];
void init()
{
    fill(flag, flag+maxn, 1);
    flag[0]=0;
    flag[1]=0;
    for(int i=2; i<=max1; i++)
    {
        if(flag[i])
        {
            cnt++;
            prime[cnt] = i;
            reprime[i] = cnt;
        }
        for(int j=1; j<=cnt&&prime[j]*i<=max1; j++)
        {
            flag[prime[j]*i] = 0;
            if(!(i%prime[j])) break;
        }
    }
}
int main()
{
    ios::sync_with_stdio(false);
    int x, y;
    init();
    while(cin>>x>>y)
    {
        while(!flag[x]) x++;
        while(!flag[y]) y--;
        // 直到x和y分别为范围内的最小和最大素数
        cout<<reprime[y]-reprime[x]+1<<endl;
    }
    return 0;
}

Problem F:NEFU1321 差点是素数

用二分来做。注意区间是否重复,如重复需要进行合并。
也听说了能用前缀和做。

就差那么两分钟就能交上了,哎呀可惜。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll maxn=1e6+1, maxdata=1e12;
int t;
ll l1, r1, l2, r2;
ll cnt=0, tot=0, prime[maxn], ans[maxn];
bool flag[maxn];
void init() // 线性素数筛
{
    fill(flag, flag+maxn, 1);
    flag[0]=0;
    flag[1]=0;
    for(ll i=2; i<maxn; i++)
    {
        if(flag[i])
        {
            prime[++cnt] = i;
        }
        for(ll j=1; j<=cnt&&prime[j]*i<=maxn; j++)
        {
            flag[prime[j]*i] = 0;
            if(!(i%prime[j])) break;
        }
    }
}
void getanswer() // 得到满足条件的数
{
    for(ll i=1; i<=cnt; i++)
        for(ll j=prime[i]*prime[i]; j<=maxdata; j*=prime[i])
            ans[tot++] = j;
    sort(ans, ans+tot);
}
ll getans(ll L, ll R)
{
    ll r = upper_bound(ans, ans+tot, R)-ans; // 上限
    ll l = lower_bound(ans, ans+tot, L)-ans; // 下限
    return r-l;
}
int main()
{
    ios::sync_with_stdio(false);
    init(); // 执行线性素数筛
    getanswer(); // 得到满足条件的数
    cin>>t;
    while(t--)
    {
        cin>>l1>>r1>>l2>>r2; // 注意区间重合情况
        if(l1>r2 || r1<l2) // 区间不重合
        {
            ll rans = getans(l1, r1)+getans(l2, r2); // 加起来算
            cout<<rans<<endl;
        }
        else // 区间重合
        {
            ll rans = getans(min(l1, l2), max(r1, r2)); // 合并区间
            cout<<rans<<endl;
        }
    }
    return 0;
}

Problem G:NEFU1669 高木同学的因子

数据没有加强,直接用gcd可以水过。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int main()
{
	ll x, y;
	cin>>x>>y;
	int m = __gcd(x, y);
	int cnt=0;
	for(int i=1; i*i<=m; i++)
		if(m%i==0) cnt++;
	if(sqrt(m)*sqrt(m) == m) cout<<cnt*2-1<<endl;
	else cout<<cnt*2<<endl;
	return 0;
}

这里有唯一分解定理版本@nefu马老三

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <string>
#include <vector>
#include <stack>
#include <bitset>
#include <cstdlib>
#include <cmath>
#include <set>
#include <list>
#include <deque>
#include <map>
#include <queue>
#include <iomanip>
using namespace std;
typedef long long ll;
const double PI = acos(-1.0);
int fx(int n)
{
    int ans = 1;
    for (int i = 2; i * i <= n; i++)
    {
        int a = 0;
        while (n % i == 0)
        {
            a++;
            n /= i;
        }
        ans *= (a + 1);
    }
    if (n > 1)
        ans *= 2;
    return ans;
}
int main()
{
    ll x, y;
    scanf("%lld%lld", &x, &y);
    int n = __gcd(x, y);
    printf("%d\n", fx(n));
    return 0;
}

Problem H:NEFU1704 知否知否,应是绿肥红瘦

模板题,注意数据范围。

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e7+1;
int cnt=0, max1=1e7, prime[maxn];
bool flag[maxn];
void init()
{
    fill(flag, flag+maxn, 1);
    flag[0]=0;
    flag[1]=0;
    for(int i=2; i<=max1; i++)
    {
        if(flag[i])
            prime[++cnt] = i;
        for(int j=1; j<=cnt&&prime[j]*i<=max1; j++)
        {
            flag[prime[j]*i] = 0;
            if(!(i%prime[j])) break;
        }
    }
}
bool judge(long long n)
{
    bool flag = 1;
    for(int i=1; prime[i]<=sqrt(n); i++)
        if(n%prime[i]==0)
        {
            flag = 0;
            break;
        }
    if(n==1) flag=0;
    return flag;
}
int main()
{
    ios::sync_with_stdio(false);
    int n;
    long long x, y, z;
    init();
    cin>>n;
    while(n--)
    {
        cin>>x>>y>>z;
        if(judge(x+y-z)) cout<<"yes"<<endl;
        else cout<<"no"<<endl;
    }
        
    return 0;
}

Problem I:NEFU2113 素数线性筛

相同题目:洛谷P3383 【模板】线性筛素数

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

模板题。

#include<bits/stdc++.h>
using namespace std;
const int maxn=4e7+1;
int cnt=0, prime[maxn];
bool flag[maxn];
void init(int max1)
{
    fill(flag, flag+max1+1, 1);
    flag[0]=0;
    flag[1]=0;
    for(int i=2; i<=max1; i++)
    {
        if(flag[i])
            prime[++cnt] = i;
        for(int j=1; j<=cnt&&prime[j]*i<=max1; j++)
        {
            flag[prime[j]*i] = 0;
            if(!(i%prime[j])) break;
        }
    }
}
int main()
{
    ios::sync_with_stdio(false);
    int n, q, k;
    cin>>n>>q;
    init(n);
    while(q--)
    {
        cin>>k;
        cout<<prime[k]<<endl;
    }
    return 0;
}

Problem J:NEFU1262 五十弦翻塞外声

套用唯一分解定理的求因子和,不过错了亿次而已。

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e6+1;
int cnt=0, max1=1e6, prime[maxn];
bool flag[maxn];
void init()
{
    fill(flag, flag+maxn, 1);
    flag[0]=0;
    flag[1]=0;
    for(int i=2; i<=max1; i++)
    {
        if(flag[i])
        {
            prime[++cnt] = i;
        }
        for(int j=1; j<=cnt&&prime[j]*i<=max1; j++)
        {
            flag[prime[j]*i] = 0;
            if(!(i%prime[j])) break;
        }
    }
}
int cas, b[100010];
long long tot=1;
void factor(int n)
{
    //cas=0;
    tot=1;
    //memset(a, 0, sizeof(a));
    //memset(b, 0, sizeof(b));
    for(int i=1; i<=cnt && prime[i]*prime[i]<=n; i++)
    {
        int s=1;
        while(!(n%prime[i]))
        {
            //b[cas]++;
            n /= prime[i];
            s *= prime[i];
        }
        tot = tot * (s*prime[i]-1) / (prime[i]-1);
        //if(b[cas]) cas++;
    }
    if(n > 1)
        tot *= (n+1);
    //    b[cas] = 1;    
}
int main()
{
    ios::sync_with_stdio(false);
    init();
    int t, n;
    cin>>t;
    while(t--)
    {
        cin>>n;
        factor(n);
        // for(int i=0; i<cas; i++)
        //     cout<<b[i]<<" ";
        cout<<tot<<endl;
    }
    return 0;
}

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

猜你喜欢

转载自blog.csdn.net/baidu_41248654/article/details/104314562