HDU 5080 Colorful Toy (polya定理)


Colorful Toy

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 262144/262144 K (Java/Others)
Total Submission(s): 454    Accepted Submission(s): 165


Problem Description
A toy is made up of N vertices and M undirected edges in the 2D plane. As usual, you want to know how many ways there are to color the vertices of the toy. You have totally C colors. And of course, to make things fun, you think that if one color configuration can be rotated to get another, these two configurations should be considered the same. Rotation means 2D in-plane rotation and reflection is not considered as rotation.


For instance, consider coloring the following toy with 2 colors. The coordinates of the vertices are:

1. (0,0)
2. (1,0)
3. (0,1)
4. (-1,0)
5. (0,-1)

The toy has 6 edges: (1,2), (1,3), (2,3), (3,4), (4,5), (5,2).

As a 2D being, this toy has no symmetry. So there are 32 ways to color it. Had the first two edges been removed, there would be only 12 different ways.

You should output the answer modulo 109 + 7.
 

Input
The first line contains an integer T (T ≤ 20) denoting the number of the test cases.

Each test case begins with three positive integers N (1 ≤ N ≤ 50), M (0 ≤ M ≤ N (N - 1)/2) and C(1 ≤ C ≤ 100).

Then follow N lines. Each line contains 2 integers in range [-10000,10000] describing a vertex.

Then follow M lines. Each line contains 2 integers in range [1,N] representing an edge. There are neither duplicate edges nor self-loops.
 

Output
For each test case, output one line containing the answer.
 

Sample Input
2 5 6 2 0 0 1 0 0 1 -1 0 0 -1 1 2 1 3 2 3 3 4 4 5 5 2 5 4 2 0 0 1 0 0 1 -1 0 0 -1 2 3 3 4 4 5 5 2
 

Sample Output
32 12
 

Source
 



2014年鞍山區域賽的一道題。題意:給n個點以及n個點的座標,還有m條邊。問給這個圖形染色共有多少種方案(旋轉後相同被視爲一種情況)。由於每個點的座標都是整數,所以原圖形只可能通過旋轉90度,180度,270度後與自身重合,只有這三種情況可能會算重。所以只需要判斷這三種情況下旋轉圖形後是否與原圖形完全一樣即可。首先,先找到圖形的中心點,然後將每個點座標減去中心點座標,相當於將圖形移動到原點。然後枚舉三種情況下,觀察旋轉後的圖形是否與原來圖形完全重合(先判斷點,後判斷邊),同時將原來圖形每個點的new_num更新成當前旋轉後對應的是哪個點。然後得到perm序列,然後運用polya定理即可求解。

polya定理,可用來用m種顏色染一個圖形共有多少種方法,需要知道對應的置換羣,對於每種置換方法求出有多少個循環節,記爲f[i],答案就是( ∑m^a[i] )/總置換方法數|G| .





#include<cstdio>
#include<cstring>
#include<cmath>
#define ll long long
#define N 1000005
#define eps 0.000000000001
#define maxn 5000
using namespace std;
const long long mod=1000000007;
long long n,m,c;
struct node{
    double x,y;
    double new_x,new_y;
    int num;
    int new_num;
}a[maxn];
int vis[maxn];
bool map[maxn][maxn];
int perm[maxn];
long long mul_pow(long long aa,long long bb)
{
    long long d,t;

    d=1;
    t=aa;
    while (bb>0)
    {
        if (bb%2==1)
            d=(d*t)%mod;
        bb/=2;
        t=(t*t)%mod;
    }

    return d;
}
ll DFS()
{
    int pos;
    ll sum=0;
    memset(vis,0,sizeof(vis));

    for(int i=1;i<=n;i++)
    {
        perm[i]=a[i].new_num;
    }
    for(int i=1;i<=n;i++)
    {


        if(!vis[i])
        {
             sum++;
            pos=i;
            for(int j=1;!vis[perm[pos]];j++)
            {   pos=perm[pos];
                vis[pos]=1;
            }
        }
    }
    return sum;
}


int main()
{

	//freopen("E:in.txt","r",stdin);

	//freopen("E:out1.txt","w",stdout);
    int T;
    double x,y,xx,yy;
    scanf("%d",&T);
    while(T--)
    {
        memset(map,0,sizeof(map));
        memset(a,0,sizeof(a));

        xx=0.0;yy=0.0;
        scanf("%I64d%I64d%I64d",&n,&m,&c);
        for(int i=1;i<=n;i++)
        {
            scanf("%lf%lf",&x,&y);
            a[i].x=x;a[i].y=y;
            xx+=x;yy+=y;
            a[i].num=i;
        }
        xx=xx/((double)n);yy=yy/((double)n);
        for(int i=1;i<=n;i++)
        {
            a[i].x-=xx;a[i].y-=yy;
        }

        int u,v;
        for(int i=1;i<=m;i++)
        {

            scanf("%d%d",&u,&v);
            map[u][v]=1;map[v][u]=1;
        }

        int tmp=1;
        long long ans=0;
        ans=mul_pow(c,n);
        for(int ca=1;ca<=3;ca++)
        {
            int flag=0;
            for(int i=1;i<=n;i++)
            {

            if(flag)
             break;



                if(ca==1)
                {
                    a[i].new_x=a[i].y;a[i].new_y=-a[i].x;
                }
                if(ca==2)
                {
                    a[i].new_x=-a[i].x;a[i].new_y=-a[i].y;
                }
                if(ca==3)
                {
                    a[i].new_x=-a[i].y;a[i].new_y=a[i].x;                }

                int fuck=0;

                for(int j=1;j<=n;j++)
                {
                    if(fabs(a[i].new_x-a[j].x)<eps&&fabs(a[i].new_y-a[j].y)<eps)
                    {
                        fuck=1;
                        a[j].new_num=i;
                        break;
                    }
                   // else flag=1;
                }
                if(fuck==0)
                    flag=1;


            }
            if(flag)
                continue;
            for(int i=1;i<=n;i++)
            {
                if(flag)
                    break;
                for(int j=1;j<=n;j++)
                {
                if(map[i][j]!=map[a[i].new_num][a[j].new_num])
                {
                    flag=1;break;
                }
                }
            }
            if(flag)
                continue;
            tmp++;
            ll now=DFS();
            ans+=mul_pow(c,now);
            ans%=mod;



        }
        ans=ans*(mul_pow(tmp,mod-2))%mod;
        printf("%I64d\n",ans);
    }

}











發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章