HDU 5080 Colorful Toy (polya定理)

1 篇文章 0 订阅
1 篇文章 0 订阅


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 10 9 + 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);
    }

}











  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值