南京理工大学第八届程序设计大赛 count_prime
2016-04-17 21:21
260 查看
题目抽象:
求出 [1,n]区间, 有多少个数字和k互素。 (不是原题,反正解决这个问题,就解决原题了)
对k分解质因数, 假设素因子为a,b,c,d。 那么只要一个数字,不包含a,b,c,d,就可以和k互素。
我们可以求出【不互素】的数字的数量, 就是a,b,c,d的整数倍的数字~~
显然a,2a,3a,4a,5a.... b,2b,3b,4b,5b...之类都是
但是a*b,a*b*c 也是。。所以容斥一下就行啦~~
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <algorithm>
#include <vector>
#include <map>
using namespace std;
#define read(a) scanf("%d", &(a))
long long prim[32000], totprim=0;
long long isprim[32000]={0};
const int haha=32003;
int n;
void predoit()
{
for (int i = 2; i != haha; ++ i)
if (isprim[i] == 0)
{
prim[totprim++] = i;
for (int j = i + i; j <= haha; j += i)
isprim[j] = 1;
}
// cout << totprim << endl;
// for (int i = 0; i <= 100; ++ i) cout << prim[i]<<" ";cout<<endl;
}
bool vis[haha + 100];
int usd[32000];
int tail=0;
#define LL long long
LL dfs(int deep, int choose, LL totnum, LL dairu)
{
//cout << deep<<" " << choose << " " << totnum<<" " <<dairu<<endl;
LL ret = 0;
if (deep == tail)
{
if (choose == 0) return 0;
if (choose % 2 == 0) return - dairu/totnum;
else return dairu/totnum;
}
ret += dfs(deep + 1, choose, totnum, dairu);
ret += dfs(deep + 1, choose + 1, totnum * usd[deep], dairu);
return ret;
}
long long get(long long p)
{
tail = 0;
for (int i = 0; i != totprim; ++ i)
if (vis[i])
{
usd[tail++] = prim[i];
}
//for (int i = 0 ; i != tail;++i) cout<< usd[i]<<" ";cout<<endl;
LL tmp =dfs(0, 0, 1, p);
// cout << tmp << endl;
return p - tmp;
}
void doit()
{
long long l, r;
scanf("%lld%lld%d", &l, &r, &n);
memset(vis, 0, sizeof(vis));
for (int i = 0; i != totprim; ++ i)
if (n % prim[i] == 0)
{
vis[i] = 1;
//cout <<"!"<< prim[i] << endl;
}
//cout << get(r) << endl;
//cout << get(l) << endl;
//get(r);
printf("%lld\n", get(r) - get(l - 1));
}
int main()
{
predoit();
int T;
read(T);
while (T--)
{
doit();
}
return 0;
}
求出 [1,n]区间, 有多少个数字和k互素。 (不是原题,反正解决这个问题,就解决原题了)
对k分解质因数, 假设素因子为a,b,c,d。 那么只要一个数字,不包含a,b,c,d,就可以和k互素。
我们可以求出【不互素】的数字的数量, 就是a,b,c,d的整数倍的数字~~
显然a,2a,3a,4a,5a.... b,2b,3b,4b,5b...之类都是
但是a*b,a*b*c 也是。。所以容斥一下就行啦~~
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <algorithm>
#include <vector>
#include <map>
using namespace std;
#define read(a) scanf("%d", &(a))
long long prim[32000], totprim=0;
long long isprim[32000]={0};
const int haha=32003;
int n;
void predoit()
{
for (int i = 2; i != haha; ++ i)
if (isprim[i] == 0)
{
prim[totprim++] = i;
for (int j = i + i; j <= haha; j += i)
isprim[j] = 1;
}
// cout << totprim << endl;
// for (int i = 0; i <= 100; ++ i) cout << prim[i]<<" ";cout<<endl;
}
bool vis[haha + 100];
int usd[32000];
int tail=0;
#define LL long long
LL dfs(int deep, int choose, LL totnum, LL dairu)
{
//cout << deep<<" " << choose << " " << totnum<<" " <<dairu<<endl;
LL ret = 0;
if (deep == tail)
{
if (choose == 0) return 0;
if (choose % 2 == 0) return - dairu/totnum;
else return dairu/totnum;
}
ret += dfs(deep + 1, choose, totnum, dairu);
ret += dfs(deep + 1, choose + 1, totnum * usd[deep], dairu);
return ret;
}
long long get(long long p)
{
tail = 0;
for (int i = 0; i != totprim; ++ i)
if (vis[i])
{
usd[tail++] = prim[i];
}
//for (int i = 0 ; i != tail;++i) cout<< usd[i]<<" ";cout<<endl;
LL tmp =dfs(0, 0, 1, p);
// cout << tmp << endl;
return p - tmp;
}
void doit()
{
long long l, r;
scanf("%lld%lld%d", &l, &r, &n);
memset(vis, 0, sizeof(vis));
for (int i = 0; i != totprim; ++ i)
if (n % prim[i] == 0)
{
vis[i] = 1;
//cout <<"!"<< prim[i] << endl;
}
//cout << get(r) << endl;
//cout << get(l) << endl;
//get(r);
printf("%lld\n", get(r) - get(l - 1));
}
int main()
{
predoit();
int T;
read(T);
while (T--)
{
doit();
}
return 0;
}
相关文章推荐
- 【设计模式】单一职责原则 & 开放封闭原则
- web标准的理解
- 苹果官方iPhone应用高级开发课程(16集)
- UFLDL 笔记 02 Backpropagation Algorithm 反向传播及初始值设置
- Centos6/7下静默安装oracle10g
- Java开发人员必须知道和了解的案头网站
- Linux 文件基本属性
- Js 标签云
- xxe漏洞简介
- MySql 单表的查询sql语句(一)
- 【NOIP practice】BSOJ 3851 计算概率 智力题——加法原理
- Web登陆实例-—同步username
- 进度条06
- js屏幕触控,手机屏幕触摸
- 20145216史婧瑶《Java程序设计》第二次实验报告
- Apple 企业开发者账号&邓白氏码申请记录
- 图片平滑处理
- mysql 导出CSV文件 并带表头
- LeetCode-7. Reverse Integer
- Java基础