hdu 5080 Colorful Toy 鞍山现场赛

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5080

题目描述:平面上有n个点,m条边,用c种颜色染色,如果两种染色方案旋转后重合,则视为同一种染色方案。求染色方案数(n<=50)

解题思路:思路很简单,polay计数定理的裸替。难点是这道题和几何联系在一起。现场赛的时候真的是有点晕了。。。。只要改一点就可以了

具体来说就是,如果旋转之后能重合,那么旋转中心一定是这n个点的中心。而且n只有50,怎么搞都可以,不论你是排序还是不排序都可以做。而且clj说只有旋转PI/2的整数倍才能重合(唉,弱渣就是弱)

还有一个很坑的地方,也就是我一直wa的地方,除法取模,要求逆元!!!!

ok,就这么多,而且应该没有重点。。

还好是打*,不然真的就跪了。。。

//#pragma comment(linker,"/STACK:102400000,102400000")
#include<stdio.h>
#include<iostream>
#include<string.h>
#include<math.h>
#include<algorithm>
#include<vector>
#include<map>
#include<set>
#include<queue>
#include<string>
#define ll long long
#define db double
#define PB push_back
#define lson k<<1
#define rson k<<1|1
using namespace std;

const int N = 55;
const db eps = 1e-8;
const db PI = acos(-1.0);
const ll MOD = 1000000007;
int n,m,mp[N][N];
bool mk[N];
ll c;

int sgn(db t)
{
    return t<-eps?-1:t>eps;
}

ll inv(ll t)
{
    ll res=1,k=MOD-2;
    while(k)
    {
        if(k&1) res=(res*t)%MOD;
        t=(t*t)%MOD;
        k>>=1;
    }
    return res;
}

struct E
{
    int a,b;
    void input()
    {
        scanf("%d%d",&a,&b);
    }
} ed[N*N];

struct P
{
    db x,y;
    int id;
    void input()
    {
        int _x,_y;
        scanf("%d%d",&_x,&_y);
        x=_x,y=_y;
    }
    P(db _x=0,db _y=0):x(_x),y(_y){}
    P rot(db thta)
    {
        return P(x*cos(thta)-y*sin(thta),
                 x*sin(thta)+y*cos(thta));
    }
    P rotByP(P ¢er,db thta)
    {
        P tmp(x-center.x,y-center.y);
        P ans=tmp.rot(thta);
        ans=ans+center;
        return ans;
    }
    P operator + (const P &t) const
    {
        return P(x+t.x,y+t.y);
    }
    bool operator == (const P &t) const
    {
        return sgn(x-t.x)==0&&sgn(y-t.y)==0;
    }
}p[N],pb,np[N];
int pt[N];
ll g,ans;

bool check()
{
    for(int i=0;i<m;i++)
    {
        int a=ed[i].a,b=ed[i].b;
        a=pt[a],b=pt[b];
        if(mp[a][b]&&mp[b][a]){}
        else return false;
    }
    return true;
}

bool fl[N];
int find_t()
{
    memset(fl,false,sizeof(fl));
    int res=0;
    for(int i=0;i<n;i++)
    {
        if(!fl[i])
        {
            res++;
        }
        int t=i;
        while(!fl[t]) fl[t]=true,t=pt[t];
    }
    return res;
}

void dfs(int k)
{
    if(k==n)
    {
        if(check())
        {
            int t=find_t();
            g++;
            ll res=1;
            for(int i=0;i<t;i++) res=res*c%MOD;
            ans=(ans+res)%MOD;
        }
    }else
    {
        for(int i=0;i<n;i++)
            if(!mk[i]&&np[k]==p[i])
        {
            mk[i]=true;
            pt[k]=i;
            dfs(k+1);
            mk[i]=false;
        }
    }
}

int main()
{
#ifdef PKWV
    freopen("in.in","r",stdin);
#endif // PKWV
    int T;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d%I64d",&n,&m,&c);
        pb.x=pb.y=0.0;
        for(int i=0;i<n;i++)
        {
            p[i].input();
            p[i].id=i;
            pb.x+=p[i].x,pb.y+=p[i].y;
        }
        pb.x/=(db)n,pb.y/=(db)n;
        memset(mp,0,sizeof(mp));
        for(int i=0;i<m;i++)
        {
            ed[i].input();
            ed[i].a--,ed[i].b--;
            mp[ed[i].a][ed[i].b]=mp[ed[i].b][ed[i].a]=1;
        }
        ans=0,g=0;
        memset(mk,false,sizeof(mk));
        for(int i=0;i<4;i++)
        {
            for(int j=0;j<n;j++)
                np[j]=p[j].rotByP(pb,i*PI/2.0);
            dfs(0);
        }
        printf("%I64d\n",ans*inv(g)%MOD);
    }
    return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值