“Love is worth years.I like coding"
2021-8-31
题目:http://xujcoj.com/home/problem/detail/3263
几大素数筛选法:
优化埃式筛:
1.合数n的最小因子一定小于sqrt(n),因此i只需要到n/i
2.j=i*i避免重复筛选 例如写成for(int j=i+i;j<=n;j+=i) 此时6就会被2*3 ,3*2重复筛
3.时间复杂度为0(n)
void E_sieve()
{
for (int i = 2;i <= n / i; i++)
{
if (!st[i])
{
for (int j = i * i; j <= n; j += i)
{
st[j] = 1;
}
}
}
}
欧拉筛:
void euler_prim()//欧拉筛
{
for (int i = 2; i <= 100000; i++)
{
if (!num[i])
{
prime[++cnt] = i;//记录多少个素数
}
for (int j = 1; j <= cnt && i * prime[j] <= 100000; j++)
{
num[i * prime[j]]++;
if (i % prime[j] == 0)//确保只被比其小的筛选
{
break;
}
}
}
}
题解:
1.有一个状态转移 ans[j]=ans[j]+ans[j-prime[i]] 此时j的方案数等于现有方案数加上其上一个状态方案数
AC代码:
#define _CRT_SECURE_NO_WARNINGS
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e5 + 1;
const int mod = 1e8 + 7;
int num[N] = { 0 };
int prime[10000] = { 0 };
int cnt = 0;
void euler_prim()//欧拉筛
{
for (int i = 2; i <= 100000; i++)
{
if (!num[i])
{
prime[++cnt] = i;//记录多少个素数
}
for (int j = 1; j <= cnt && i * prime[j] <= 100000; j++)
{
num[i * prime[j]]++;
if (i % prime[j] == 0)//确保只被比其小的筛选
{
break;
}
}
}
}
int main()
{
euler_prim();
int T;
scanf("%d", &T);
while (T--)
{
int ans[N] = { 1 };//都包括自身的一个
int n, m;
scanf("%d %d", &n, &m);
int first = lower_bound(prime, prime + cnt, m) - prime;//获取下标
for (int i = first; i <= cnt; i++)
{
for (int j = n; j >= prime[i]; j--)
{
ans[j] = (ans[j] + ans[j - prime[i]]) % mod;//
}
}
printf("%d\n", ans[n]);
}
}