您的位置:首页 > 其它

南京理工大学第八届程序设计大赛 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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: