您的位置:首页 > 编程语言 > C语言/C++

AHOI2002黑白瓷砖_Polya定理

2014-12-17 15:29 211 查看
终于把群论的一部分刷完了, 可喜可贺! 看了三次才看懂, 果然是非蒟蒻不能为也。

题目几乎是裸题, 其中一共有6种方案, 全部找出之后上polya定理即可。 先分步, 第一步, 翻转或者不翻转; 第二步, 不旋转,旋转120°或240°。 

1、 不旋转且不翻转。 则原图中共有n*(n+1)/2个循环, 记为sum;

2、 不翻转, 旋转120°。 则原图与当前图会形成三元循环(图1), 若原图有中心砖块则还有一个单元循环(图2)。

             

 
                     


                                                     图1    
      图2

故可知循环个数 = ceil(sum/3);

3、 不翻转, 旋转240°。 与120°相同。

4、 翻转, 不旋转。 我们可以发现原图被镜面对称了, 于是以中线为轴每对对称点形成一个新的循环, 这样就有了sum2 = 1+1+2+2+...+(n+1)/2个循环。(图3)


                                                            


图3                                                                                                                                  图4

5、翻转并旋转120°。 其实这和以图中红色的线为轴的翻转是等价的(图4), 那么就和之前的情况一样共有sum2个循环。

6、翻转并旋转240°。 同上。

然后由polya定理可知等价类的个数ans = (2^sum+2*2^ceil(sum/3)+3*2^sum2) / 6, 到此结束。

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#define N 200
#define mod 10000

using namespace std;

struct node
{
int len, l
;
void clear() { len = 1; memset(l, 0, sizeof l); }
void print()
{
printf("%d", l[len]);
for (int i = len - 1; i; i--)
printf("%04d", l[i]);
putchar('\n');
}
}ans;
inline int max(int x, int y)
{
return x > y ? x : y;
}
void mul(node &a, node b)
{
node c;
c.clear();
c.len = a.len + b.len - 1;
for (int i = 1; i <= a.len; ++i)
for (int j = 1; j <= b.len; ++j)
c.l[i+j-1] += a.l[i] * b.l[j];
for (int i = 1; i <= c.len; ++i)
{
c.l[i+1] += c.l[i] / mod;
c.l[i] %= mod;
}
while(c.l[c.len+1])
{
++c.len;
c.l[c.len+1] += c.l[c.len] / mod;
c.l[c.len] %= mod;
}
a = c;
}
void plus(node &a, node b)
{
a.len = max(a.len, b.len);
for (int i = 1; i <= a.len; ++i)
{
a.l[i] += b.l[i];
a.l[i+1] += a.l[i] / mod;
a.l[i] %= mod;
}
if (a.l[a.len+1]) ++a.len;
}
void div(node &a, int b)
{
int now = 0, flag = 0;
for (int i = a.len; i; i--)
{
(now *= mod) += a.l[i];
a.l[i] = 0;
if (now < b) continue;
if (!flag)
{
flag = 1;
a.len = i;
}
a.l[i] = now / b;
now %= b;
}
}
node pow(node a, int x)
{
node tmp;
tmp.clear();
tmp.l[1] = 1;
while(x)
{
if (x & 1) mul(tmp, a);
mul(a, a);
x >>= 1;
}
return tmp;
}
int main()
{
int n, sum, now = 0;
scanf("%d", &n);
sum = n * (n+1) / 2;
node tmp;
tmp.clear();
tmp.l[1] = 2;
plus(ans, pow(tmp, sum));
plus(ans, pow(tmp, ceil((double)sum/3)+1));
for (int i = 1; i <= n; ++i)
now += (i+1) / 2;
plus(ans, pow(tmp, now));
plus(ans, pow(tmp, now));
plus(ans, pow(tmp, now));
div(ans, 6);
ans.print();
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  c++ algorithm 群论