LightOJ1197ヘルプ半蔵(オイラーシーブ+インターバルプライム)

トピックリンク

問題の説明

邪悪な精神的指導者である天草は、美しいナクルル王女を捕らえました。その理由は、最高の忍者であり、ナクルの愛である服部半蔵に少し問題があったからです。その知らせを聞いた半蔵は非常に腹を立てた。しかし、彼は賢くて頭がいいので、冷静さを保ち、天草と対峙する計画を立てました。

天草の城に到着する前に、半蔵はいくつかの領土を通過する必要があります。テリトリーには、a、a + 1、a + 2、a + 3…bの番号が付けられています。しかし、他の戦闘機が彼を待っている可能性があるため、すべての領土が半蔵にとって安全であるとは限りません。実は恐れていませんが、天草と対峙しているので、スタミナを極力抑えなければなりません。

彼は素数である領域が彼にとって安全であると計算しました。ここでaとbが与えられると、彼は自分にとって安全な領域がいくつあるかを知る必要があります。しかし、彼は他の計画で忙しいので、この小さな問題を解決するためにあなたを雇いました!

入力

入力は整数T(≤200)で始まり、テストケースの数を示します。
各ケースには、2つの整数aとb(1≤a≤b<2 ^ 31、ba≤100000)を含む行が含まれています。

出力

ケースごとに、ケース番号と安全な地域の数を印刷します。

サンプル入力

3
2 36
3 73
3 11

サンプル出力

Case 1: 11

Case 2: 20

Case 3: 4

注意

数が正確に2つの異なる整数で割り切れる場合、その数は素数であると言われます。したがって、最初のいくつかの素数は2、3、5、7、11、13、17、…

題名

0から2 ^ 31の範囲で、差が100000以下の2つの数値aとbが与えられ、2つの数値の間の素数の数が必要です。

アイデア

2 ^ 31は大きすぎるため、素数を直接ふるいにかけることはできず、他の方法を検討する必要があります。aとbの違いは限られているため、妥当な範囲内のプライム番号テーブルを使用して[a、b]を間隔[0、ba]にマッピングし、ズームインして非プライム番号としてマークすることにより、目的の間隔に復元することを検討できます。 、そして最後にそれを数えるためにトラバースします。

コード

#include<map>
#include<set>
#include<stack>
#include<queue>
#include<string>
#include<math.h>
#include<stdio.h>
#include<string.h>
#include<iostream>
#include<algorithm>
#define pb push_back
using namespace std;
//const int mod=998244353;
const int maxn=1e6+5;
typedef long long ll;
const int inf=0x3f3f3f3f;
const int minn=0xc0c0c0c0;
bool vis[maxn],flag[maxn];
ll a,b,cnt,tot,prime[maxn];
void eul(ll n)
{
    
    
	cnt=0;
	vis[1]=true;
	for(ll i=2;i<=n;i++)
	{
    
    
		if(!vis[i])
			prime[++cnt]=i;
		for(ll j=1;j<=cnt&&i*prime[j]<=n;j++)
		{
    
    
			vis[i*prime[j]]=true;
			if(i%prime[j]==0)
				break;
		}
	}
}
int main()
{
    
    
	int t;
	eul(maxn);
	scanf("%d",&t);
	for(int ca=1;ca<=t;ca++)
	{
    
    
		tot=0;
		scanf("%lld%lld",&a,&b);
		if(b<maxn)
		{
    
    
			for(ll i=a;i<=b;i++)
			{
    
    
				if(!vis[i])
					tot++;
			}
		}
		else
		{
    
    
			memset(flag,false,sizeof flag);
			for(ll i=1;i<=cnt;i++)
			{
    
    
				ll tmp=(a+prime[i]-1)/prime[i];//缩小并保证放大后不会导致a漏筛 
				for(ll j=tmp*prime[i];j<=b;j+=prime[i])
				{
    
    
					flag[j-a]=true;
				}//放大至[a,b]区间并标记 
			}
			for(ll i=0;i<=b-a;i++)
			{
    
    
				if(!flag[i])
					tot++;
			}
		}
		printf("Case %d: %lld\n",ca,tot);
	}
    return 0;
}

おすすめ

転載: blog.csdn.net/WTMDNM_/article/details/108759115