hdu 5080 2014ACM/ICPC鞍山K题 polya计数

首先,中心点是能够直接算出来的

把全部的坐标相加再除n就能够

然后枚举一个不靠近中心的点,枚举它绕中心点旋转的角度。仅仅要枚举50次就能够了

计算出当前枚举的的角度能否形成一个置换群

计算循环节,再用polya定理算个数

#pragma comment(linker, "/STACK:102400000,102400000")
#include<iostream>
#include<vector>
#include<algorithm>
#include<cstdio>
#include<queue>
#include<stack>
#include<string>
#include<map>
#include<set>
#include<cmath>
#include<cassert>
#include<cstring>
#include<iomanip>
using namespace std;
#ifdef _WIN32
#define i64 __int64
#define out64 "%I64d\n"
#define in64 "%I64d"
#else
#define i64 long long
#define out64 "%lld\n"
#define in64 "%lld"
#endif
/************ for topcoder by zz1215 *******************/
#define foreach(c,itr)  for(__typeof((c).begin()) itr=(c).begin();itr!=(c).end();itr++)
#define FOR(i,a,b)      for( int i = (a) ; i <= (b) ; i ++)
#define FF(i,a)         for( int i = 0 ; i < (a) ; i ++)
#define FFD(i,a,b)      for( int i = (a) ; i >= (b) ; i --)
#define S64(a)          scanf(in64,&a)
#define SS(a)           scanf("%d",&a)
#define LL(a)           ((a)<<1)
#define RR(a)           (((a)<<1)+1)
#define pb              push_back
#define pf              push_front
#define X               first
#define Y               second
#define CL(Q)           while(!Q.empty())Q.pop()
#define MM(name,what)   memset(name,what,sizeof(name))
#define MC(a,b)			memcpy(a,b,sizeof(b))
#define MAX(a,b)        ((a)>(b)?(a):(b))
#define MIN(a,b)        ((a)<(b)?(a):(b))
#define read            freopen("out.txt","r",stdin)
#define write           freopen("out2.txt","w",stdout)

const int inf = 0x3f3f3f3f;
const i64 inf64 = 0x3f3f3f3f3f3f3f3fLL;
const double oo = 10e9;
const double eps = 10e-6;
const double pi = acos(-1.0);
const int maxn = 55;
const int mod = 1000000007;

int n, m, c;
int nx[maxn];
int ny[maxn];
double cita[maxn];
double r[maxn];
double cx, cy;
int a[maxn];
int b[maxn];
int edge[maxn][maxn];

i64 gcd(i64 _a, i64 _b)
{
	if (!_a || !_b)
	{
		return max(_a, _b);
	}
	i64 _t;
	while ((_t = _a % _b))
	{
		_a = _b;
		_b = _t;
	}
	return _b;
}

i64 ext_gcd(i64 _a, i64 _b, i64 &_x, i64 &_y)
{
	if (!_b)
	{
		_x = 1;
		_y = 0;
		return _a;
	}
	i64 _d = ext_gcd(_b, _a % _b, _x, _y);
	i64 _t = _x;
	_x = _y;
	_y = _t - _a / _b * _y;
	return _d;
}

i64 invmod(i64 _a, i64 _p)
{
	i64 _ans, _y;
	ext_gcd(_a, _p, _ans, _y);
	_ans < 0 ?

_ans += _p : 0;
	return _ans;
}

double gao(double x,double y){
	if (abs(x) < eps){
		if (y>0){
			return pi / 2.0;
		}
		else{
			return pi + pi / 2.0;
		}
	}
	else if (x >= 0 && y >= 0){
		return atan(y / x);
	}
	else if (x <= 0 && y >= 0){
		x = -x;
		return pi - atan(y / x);
	}
	else if (x <= 0 && y <= 0){
		x = -x;
		y = -y;
		return pi + atan(y / x);
	}
	else {
		y = -y;
		return 2 * pi - atan(y / x);
	}
}

int find(double tcita,double tr){
	if (tcita > 2 * pi){
		tcita -= 2 * pi;
	}
	double tx = cx + tr*cos(tcita);
	double ty = cy + tr*sin(tcita);
	for (int i = 1; i <= n; i++){
		if (abs(tx - nx[i]) < eps && abs(ty-ny[i]) < eps){
			return i;
		}
	}
	return -1;
}

bool isint(double temp){
	int t2 = temp;
	temp -= t2;
	if (temp < eps) {
		return true;
	}
	else{
		return false;
	}
}

bool can(){
	int now, to;
	for (int x = 1; x <= n; x++){
		for (int y = 1; y <= n; y++){
			now = b[x];
			to = b[y];
			if (edge[x][y] != edge[now][to]){
				return false;
			}
		}
	}
	return true;
}

bool vis[maxn];

int count(){
	MM(vis, 0);
	int re = 0;
	int now, to;
	for (int x = 1; x <= n; x++){
		if (!vis[x]){
			now = x;
			vis[now] = true;
			re++;
			while (true){
				to = b[now];
				if (vis[to]){
					break;
				}
				else{
					vis[to] = true;
					now = to;
				}
			}
		}
	}
	return re;
}

i64 pow_mod(int x,int temp){
	i64 re = 1;
	for (int i = 1; i <= temp; i++){
		re *= x;
		re %= mod;
	}
	return re;
}

i64 start(){
	cx = 0.0;
	cy = 0.0;
	for (int i = 1; i <= n; i++){
		cx += nx[i];
		cy += ny[i];
	}
	cx /= n;
	cy /= n;
	double tx, ty;
	for (int i = 1; i <= n; i++){
		tx = nx[i] - cx;
		ty = ny[i] - cy;
		r[i] = sqrt(tx*tx + ty*ty);
		cita[i] = gao(tx, ty);
	}
	double spin;
	i64 ans = 0;
	i64 sg =0;
	int id;
	for (int i = 1; i <= n; i++){
		if (abs(cx - nx[i]) > eps || abs(cy - ny[i]) > eps){
			id = i;
			break;
		}
	}
	for (int i = 1; i <= n; i++){
		spin = cita[i] - cita[id];
		if (abs(r[i] - r[id]) < eps){
			bool no = false;
			for (int x = 1; x <= n; x++){
				a[x] = find(cita[x] + spin, r[x]);
				if (a[x] == -1){
					no = true;
					break;
				}
				b[a[x]] = x;
			}
			if (no) continue;
			if (can()){
				sg++;
				ans += pow_mod(c, count());
				ans %= mod;
			}
		}
	}
	ans *= invmod(sg, mod);
	ans %= mod;
	return ans;
}

int main(){
	int T;
	cin >> T;
	while (T--){
		cin >> n >> m >> c;
		for (int i = 1; i <= n; i++){
			cin >> nx[i] >> ny[i];
		}
		for (int i = 0; i <= n; i++){
			for (int j = 0; j <= n; j++){
				edge[i][j] = 0;
			}
		}
		int now, to;
		for (int i = 1; i <= m; i++){
			cin >> now >> to;
			edge[now][to] = edge[to][now] = 1;
		}
		if (n == 1){
			cout << c << endl;
			continue;
		}
		i64 ans = start();
		cout << ans << endl;
	}
	return 0;
}
时间: 2024-10-14 09:51:37

hdu 5080 2014ACM/ICPC鞍山K题 polya计数的相关文章

2017 ACM/ICPC 沈阳 K题 Rabbits

Here N (N ≥ 3) rabbits are playing by the river. They are playing on a number line, each occupying a different integer. In a single move, one of the outer rabbits jumps into a space between any other two. At no point may two rabbits occupy the same p

hdu5080:几何+polya计数(鞍山区域赛K题)

/* 鞍山区域赛的K题..当时比赛都没来得及看(反正看了也不会) 学了polya定理之后就赶紧跑来补这个题.. 由于几何比较烂写了又丑又长的代码,还debug了很久.. 比较感动的是竟然1Y了.. */ 题目大意: 给定一些点,某些点上有边,问用k种颜色染色的等价类有多少种 思路: 由于坐标是整数..只有可能旋转90,180,270才能得到置换 且图形必须为中心对称图形 先用几何方法找出对称中心 然后旋转,找是否出现置换... 由于点数只有50,几何预处理这一部分可以很暴力无脑的写..各种判断相

2014ACM/ICPC亚洲区鞍山赛区现场赛——题目重现

2014ACM/ICPC亚洲区鞍山赛区现场赛--题目重现 题目链接 5小时内就搞了5题B.C.D.E,I. H题想到要打表搞了,可惜时间不够,后面打出表试了几下过了- - K题过的人也比较多,感觉是个几何旋转+ploya,但是几何实在不行没什么想法 B:这题就是一个大模拟,直接数组去模拟即可,注意细节就能过 C:类似大白上一题红蓝三角形的, 每个数字找一个互质和一个不互质个数,除掉重复就直接除2,然后总的C(n, 3)减去即可,问题在怎么处理一个数字互质和不互质的,其实只要处理出不互质的即可,这

HDU 5006 Resistance(鞍山网络赛J题)

HDU 5006 Resistance 思路:这题由于数据是随机的..电阻不是1就是0,就可以先缩点,把电阻为0的那些边缩掉,只考虑有电阻的边,这样的话缩下来点数就不多了,就可以利用高斯消元+基尔霍夫定律去搞了 代码: #include <cstdio> #include <cstring> #include <cmath> #include <vector> #include <algorithm> using namespace std; c

hdu 1812 Count the Tetris polya计数

哈哈哈,简单polya,公式自己推导. 不过这题需要用到大数,很久没写Java,调了好久. import java.math.*; import java.util.*; import java.io.*; public class Main{ public static void main(String args[]){ Scanner cin=new Scanner(System.in); int n; BigInteger c; while(cin.hasNextInt()) { BigI

hdu 1999 不可摸数 水题。

不可摸数 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 7966    Accepted Submission(s): 2024 Problem Description s(n)是正整数n的真因子之和,即小于n且整除n的因子和.例如s(12)=1+2+3+4+6=16.如果任何数m,s(m)都不等于n,则称n为不可摸数. Input 包

HDU 4862 Jump(最小K路径覆盖)

输入一个n×m网格图,每个结点的值为0-9,可以从任意点出发不超过k次,走完每个点且仅访问每个结点一次,问最终的能量最大值.不可全部走完的情况输出-1. 初始能量为0. 而结点(x,y)可以跳跃到结点(x,y+dy)或(x+dx,y).消耗能量为跳跃前后结点的曼哈顿距离 - 1 .若跳跃前后的结点的值相等,能量加上那个值. 具体建图可以参考这里http://blog.sina.com.cn/s/blog_6bddecdc0102uy9g.html 最小K路径覆盖其实在之前是见过的打过的,不过这次

HDU 4085 斯坦纳树模板题

Dig The Wells Time Limit: 6000/2000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 971    Accepted Submission(s): 416 Problem Description You may all know the famous story "Three monks". Recently they find som

HDU 4633(polya计数

题目:用k种颜色给一个魔方染色,可以染每个面的9个小矩形,12条棱,8个顶点(总之就是有74个能染的地方),空间旋转后一样的视为相同,问有多少种不同的染色方案. 思路:裸的polya计数,但是这个立方体的对称群本来就很容易弄错...<组合数学>里有个例题提到立方体的对称群有24个元素,分别是: (1)恒等变换. (2)以两个相对面的中心相连作为对称轴,旋转(i)90,(ii)180,(iii)270度,每种有3个.共9种. (3)以两个相对棱的中点连线为对称轴翻转180度,有6种. (4)固定