您的位置:首页 > 运维架构

2014 鞍山区域赛 C HDU5072 Coprime 莫比乌斯/容斥+同色三角形

2016-07-13 10:22 316 查看
题意:n个数中,求三个数两两互质或者两两不互质的三元组的数量;

思路:单色三角形模型,也就是说完全图中,每两点间的边可以是黑色,可以是红色,求纯色三角形的数量;

直接求会非常困难,所以我们转化为对偶问题——求不纯色三角形的数量;

来关注某个三角形ABC,假设A固定,那么我们可以假设,A与B互质,A与C不互质,这时我们不用关心B与C之间是否互质,因为不影响结果;注意A不能是1,因为所有数都与1互质;

所以我们只需要对于每个数i,算出与之不互质的数ki,所以与之互质的数为n-ki-1个,又因为每个因此结果就是sigma(ki*(n-ki-1))/2,i=1…n;

于是题目就转换成了在某个集合中,快速求出与每个数不互质的数的个数,于是做法自然是莫比乌斯函数/容斥了;

先说比较好理解的容斥——对于每个数提取出因数,则比如求与30不互质的数,ki=num(2)+num(3)+num(5)-num(6)-num(10)-num(15)+num(30)-1;

容斥代码:

#define _CRT_SECURE_NO_WARNINGS
#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<ctime>
#include<cctype>

#include<iostream>
#include<vector>
#include<map>
#include<queue>
#include<string>
#include<set>
#include<algorithm>
#include<stack>
//#pragma comment(linker, "/STACK:102400000,102400000")
using namespace std;

#define mem(a,b) memset(a,b,sizeof(a))
#define INF 0x7fffffff
#define ll long long
#define eps 1e-5
#define pii pair<int,int>
#define pll pair<ll,ll>
#define m_p make_pair
#define PI 2.0*acos(0.0)
#define MOD 1000000007

#define MAXN 1000

int numc[100*MAXN+5];
int factor[20], fac;
int f[100*MAXN+5];
ll sum;
int prime[MAXN], isprime[MAXN], num;

void getprimes()
{
num = 0;
//mem(prime, 0);
mem(isprime, 1);
for (int i = 2; i < MAXN; i++){
if (isprime[i])
prime[num++] = i;
for (int j = 1; j<num && i*prime[j] <= MAXN; j++){
isprime[i*prime[j]] = 0;
if (i%prime[j] == 0) break;
}
}
}

void dfs1(int now, int s)
{
if (now == fac)
{
numc[s]++;
return;
}
dfs1(now + 1, s);
dfs1(now + 1, s*factor[now]);
}

void dfs2(int id, int all, int now, int s)
{
if (now == all)
{
sum += numc[s];
return;
}
if (id < fac)
{
dfs2(id + 1, all, now + 1, s*factor[id]);
dfs2(id + 1, all, now, s);
}
}

void getfactors(int n)
{
fac = 0;
for (int i = 0; i < num&&prime[i] <= n; i++)
{
if (n%prime[i] == 0)
{
factor[fac++] = prime[i];
while (n%prime[i] == 0) n /= prime[i];
}
}
if (n > 1) factor[fac++] = n;
}

int main()
{
getprimes();
int T;
cin >> T;
while (T--)
{
int n;
cin >> n;
mem(numc, 0);
for (int i = 1; i <= n; i++)
{
scanf("%d", &f[i]);
getfactors(f[i]);
dfs1(0, 1);
}
ll ans = 0;
for (int i = 1; i <= n; i++)
{
getfactors(f[i]);
ll ret = 1;
ll tmp = 0;
for (int j = 1; j <= fac; j++)
{
sum = 0;
dfs2(0, j, 0, 1);
tmp += ret*sum;
ret = -ret;
}
if (tmp == 0)
{
continue;
}
ans += (tmp - 1)*(n - tmp);
}
cout << (ll)n*(n - 1)*(n - 2) / 6 - ans / 2 << endl;
}
}

然后是不怎么容易理解的莫比乌斯函数——
等会再写解析QAQ

#define _CRT_SECURE_NO_WARNINGS
#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<ctime>
#include<cctype>

#include<iostream>
#include<vector>
#include<map>
#include<queue>
#include<string>
#include<set>
#include<algorithm>
#include<stack>
//#pragma comment(linker, "/STACK:102400000,102400000")
using namespace std;

#define mem(a,b) memset(a,b,sizeof(a))
#define INF 0x7fffffff
#define ll long long
#define eps 1e-5
#define pii pair<int,int>
#define pll pair<ll,ll>
#define m_p make_pair
#define PI 2.0*acos(0.0)
#define MOD 1000000007

#define N 100005

int n, a
, u
;
int pri
, pz;
bool ispri
;
ll ans, c
;

void Pre() {
u[1] = 1;
for (int i = 2; i < N;i++) {
if (!ispri[i]) {
pri[++pz] = i;
u[i] = -1;
}
for (int j = 1; j <= pz;j++) {
int k = i * pri[j];
if (k > N) break;
ispri[k] = 1;
u[k] = -u[i];
if (i % pri[j] == 0) {
u[k] = 0;
break;
}
}
}
}

int main()
{
Pre();
int T;
cin >> T;
while (T--)
{
scanf("%d", &n);
mem(a, 0);
mem(c, 0);
ans = 0;
int x;
for (int i = 1; i <= n; i++)
{
scanf("%d", &x);
a[x]++;
}
for (int i = 2; i < N; i++)
{
int num = 0;
for (int j = i; j < N; j += i)
{
num += a[j];
}
for (int j = i; j < N; j += i)
{
c[j] -= u[i] * num;
}
}
for (int i = 2; i < N; i++)
c[i] -= a[i];
for (int i = 1; i < N; i++)
{
x = n - a[i] - c[i];
ans += ((c[i] * a[i]) + (a[i] * (a[i] - 1))) * x;
}
cout << (ll)(n)* (n - 1) * (n - 2) / 6 - ans / 2 << endl;
}

return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息