Cod sursa(job #25234)

Utilizator gcosminGheorghe Cosmin gcosmin Data 4 martie 2007 11:33:22
Problema Puteri Scor 90
Compilator cpp Status done
Runda preONI 2007, Runda 3, Clasa a 10-a Marime 2.84 kb
#include <stdio.h>
#include <algorithm>
#include <string.h>
#include <vector>
#include <bitset>
using namespace std;

#define NMAX 100010

long long rez = 0;

int N, stepmax;

int pr[300];

int a[NMAX];
int b[NMAX];
int c[NMAX];
int d[NMAX];

char am[NMAX];
char bm[NMAX];
char cm[NMAX];

bitset <2100000> ap;
int kkt[2100000];

int prim(int x)
{
	int i;

	for (i = 2; i * i <= x; i++)
		if (x % i == 0) return 0;

return 1;
}

inline int srch(int q)
{
	int step = stepmax, x = 0;

	for (; step; step >>= 1)
		if (x + step <= N && d[x + step] <= q)
			x += step;
	
return x;
}

long long numar(int x)
{
	// numar cate perechi dau toate alea divizibile la x

	int i;

	long long rez = 0;

	ap = 0;

	for (i = 1; i <= N; i++) {
//		if (x > a[i]) am[i] = a[i]; else am[i] = a[i] % x; 
//		if (x > b[i]) bm[i] = b[i]; else bm[i] = b[i] % x; 
//		if (x > c[i]) cm[i] = c[i]; else cm[i] = c[i] % x;
		am[i] = a[i]; while (am[i] >= x) am[i] -= x;
		bm[i] = b[i]; while (bm[i] >= x) bm[i] -= x;
		cm[i] = c[i]; while (cm[i] >= x) cm[i] -= x;
		
		d[i] = (am[i] << 14) + (bm[i] << 7) + cm[i] % x;
		if ((2 * a[i]) % x == 0 && (2 * b[i] % x == 0) && (2 * c[i] % x == 0)) rez--;
//		if ( (am[i] + am[i] == x || am[i] + am[i] == 2 * x) && (bm[i] + bm[i] == x || bm[i] + bm[i] == 2 * x) && (cm[i] + cm[i] == x || cm[i] + cm[i] == 2 * x)) rez--;

		if (!ap[d[i]]) kkt[d[i]] = 0;
		kkt[d[i]]++;
		ap[d[i]] = 1;
	}

//	sort(d + 1, d + N + 1);

	int aa, bb, cc, nnr;

	for (i = 1; i <= N; i++) {
		aa = x - am[i]; if (aa == x) aa = 0;
		bb = x - bm[i]; if (bb == x) bb = 0;
		cc = x - cm[i]; if (cc == x) cc = 0;

		nnr = (aa << 14) + (bb << 7) + cc;

		if (!ap[nnr]) continue;

		rez += kkt[nnr];
	}

	return (rez >> 1);
}

void back(int k, int last, int nr)
{
	if (nr != 1) {
		if (k & 1) rez += numar(nr);
		else rez -= numar(nr);
	}

	int i;
	for (i = last + 1; i <= pr[0]; i++) 
		if (nr * pr[i] <= 128) back(k + 1, i, nr * pr[i]);
}

int gen(int N)
{
	freopen("puteri.in", "w", stdout);
	
	printf("%d\n", N);

	int i;
	for (i = 1; i <= N; i++) printf("%d %d %d\n", rand() % 64, rand() % 64, rand() % 64);
fclose(stdout);
return 0;
}

int cmmdc(int a, int b)
{
	if (a == 0) return b;
	if (b == 0) return a;
	return cmmdc(b, a % b);
}

void get_brute()
{
	int i, j, aa, bb, cc, rez = 0;

	for (i = 1; i <= N; i++)
		for (j = i + 1; j <= N; j++) {
			aa = a[i] + a[j]; bb = b[i] + b[j]; cc = c[i] + c[j];
			if (cmmdc(cmmdc(aa, bb), cc) != 1) rez++;
		}

	printf("%d\n", rez);
}

int main()
{
//	srand(666);
//	gen(10000);
	
	int i;
	
	freopen("puteri.in", "r", stdin);
	freopen("puteri.out", "w", stdout);

	for (i = 2; i <= 128; i++) if (prim(i)) pr[++pr[0]] = i;
	
	scanf("%d", &N);

	for (stepmax = 1; stepmax <= N; stepmax <<= 1); stepmax >>= 1;

	for (i = 1; i <= N; i++) scanf("%d %d %d", &a[i], &b[i], &c[i]);

	back(0, 0, 1);

	printf("%lld\n", rez);

//	get_brute();

fclose(stdin);
fclose(stdout);
return 0;
}