/*
鞍山区域赛的K题。。当时比赛都没来得及看(反正看了也不会)
学了polya定理之后就赶紧跑来补这个题。。
由于几何比较烂写了又丑又长的代码,还debug了很久。。
比较感动的是竟然1Y了。。
*/
题目大意:
给定一些点,某些点上有边,问用k种颜色染色的等价类有多少种
思路:
由于坐标是整数。。只有可能旋转90,180,270才能得到置换
且图形必须为中心对称图形
先用几何方法找出对称中心
然后旋转,找是否出现置换。。。
由于点数只有50,几何预处理这一部分可以很暴力无脑的写。。各种判断相等即可
得到置换数和每个置换的循环数之后用polya定理的公式求和即可(取模需要逆元)
代码:
#include <iostream> #include <stdio.h> #include<string.h> #include<algorithm> #include<string> #include<math.h> #include<ctype.h> using namespace std; #define esp 0.0000000001 #define mod 1000000007 bool isequal(double a,double b) { if(fabs(a-b)<esp) return 1; return 0; } struct point { double x,y; bool operator ==(point a) { return (isequal(x,a.x)&&isequal(y,a.y)); } void rotate(point o) { double y1=y-o.y; double x1=x-o.x; x=o.x+y1; y=o.y-x1; } }O,p[55],q[55]; struct edge { int a,b; bool operator ==(edge t) { return ((p[a]==q[t.a]&&p[b]==q[t.b])||(p[b]==q[t.a]&&p[a]==q[t.b])); } }e[2510]; //// int g,r[55],n,m,k,rev[5]; long long exgcd(long long a,long long b,long long &x,long long &y) { if(a==0&&b==0) return -1; if(b==0){x=1;y=0;return a;} long long d=exgcd(b,a%b,y,x); y-=a/b*x; return d; } //*********求逆元素******************* //ax = 1(mod n) long long inv(long long a,long long n) { long long x,y; long long d=exgcd(a,n,x,y); if(d==1) return (x%n+n)%n; else return -1; } long long quickmod(long long a,long long b,long long m) //a^b%m { long long res=1; while(b) { if(b&1) res=res*a%mod; b>>=1; a=a*a%mod; } return res; } point mid(point a,point b) { point res; res.x=(a.x+b.x)/2; res.y=(a.y+b.y)/2; return res; } point sym(point a,point o) { point res; double x1=o.x-a.x; double y1=o.y-a.y; res.x=o.x+x1; res.y=o.y+y1; return res; } int yes(int i,int j) { int ok=1; point tmp; for(int i=0;i<n;i++) { tmp=sym(p[i],O); int j; for(j=0;j<n;j++) { if(p[j]==tmp) { break; } } if(j==n) { ok=0; break; } } return ok; } int findo() { int ok=0; for(int i=0;i<n;i++) { for(int j=i+1;j<n;j++) { O=mid(p[i],p[j]); if(yes(i,j)) { ok=1; break; } } if(ok) break; } return ok; } int check() { int ok=1; for(int i=0;i<m;i++) { int j; for(j=0;j<m;j++) { if(e[j]==e[i]) { break; } } if(j==m) { ok=0; break; } } return ok; } int findrev() { int ok=1; for(int i=0;i<n;i++) { int j; for(j=0;j<n;j++) { if(p[i]==q[j]) { r[i]=j; break; } } if(j==n) ok=0; if(ok==0) break; } return ok; } int findloop() { int res=0; bool vi[55]; memset(vi,0,sizeof(vi)); for(int i=0;i<n;i++) { if(!vi[i]) { for(int j=i;;j=r[j]) { vi[j]=1; if(r[j]==i) { break; } } res++; } } return res; } void reverse() { rev[0]=n; g=1; if(!findo()) { return; } memcpy(q,p,sizeof(q)); for(int i=1;i<=3;i++) { for(int j=0;j<n;j++) { q[j].rotate(O); } if(check()) { if(findrev()) rev[g++]=findloop(); } } } void ini() { scanf("%d%d%d",&n,&m,&k); for(int i=0;i<n;i++) { scanf("%lf%lf",&p[i].x,&p[i].y); } for(int i=0;i<m;i++) { scanf("%d%d",&e[i].a,&e[i].b); e[i].a--; e[i].b--; } } void solve() { reverse(); long long ans=0; for(int i=0;i<g;i++) { ans+=quickmod(k,rev[i],mod); ans%=mod; } if(g==4) { ans*=inv(2,mod); ans%=mod; ans*=inv(2,mod); ans%=mod; } else { ans*=inv(g,mod); ans%=mod; } printf("%I64d\n",ans); } int main() { //freopen("in.txt","r",stdin); int t; scanf("%d",&t); while(t--) { ini(); solve(); } return 0; }