2018.07.12【2018提高组】模拟B组 【NOIP2015模拟10.27】魔法阵

#Description
帕秋莉·诺蕾姬,有着“不动的大图书馆” 的称号,擅长使用各种各样的属性魔法。
——《东方求闻史记》
一如既往地,帕秋莉在图书馆中研究着魔法。今天,她在研究一本魔法书中的法阵。
这个法阵可以看成是按下面的规则生成一个规模为n(n 为非负整数) 的图形:

  1. 在直角坐标系xOy 中,画4 条线段:[(0,0), (2^n,0)], [(0, 0), (-2^n, 0)],[(0, 0), (0, 2^n)], [(0, 0), (0,-2^n)]。
  2. 对于所有的i = 1, 2, …, n,画两个正方形,一个以(0, 2^i), (0,-2i),(2i, 0), (-2^i, 0) 为顶点,另一个以(-2i-1,-2i-1),(-2i-1,2i-1), (2i-1,-2i-1)(2i-1,2i-1) 为顶点。
  3. 画一个以(1, 0), (-1, 0), (0,-1), (0, 1) 为顶点的正方形。
    比如,当n = 0 时的法阵是这样的:
    这里写图片描述
    当n = 2 时的法阵是这样的:
    这里写图片描述
    帕秋莉已经画出了这个巨大的法阵, 并且她能够同时控制k 种不同的属性元素。接下来,她要将这k 种元素分别依次灌注进法阵中的k 个不重叠不相交的三角形中,即这k 个三角形要灌注进不同的元素。这样,这个法阵就会被激活。
    然而,灌注的方法有许多种。为了能最大限度地进行实验,帕秋莉想把所有的方法都实验一遍。而摆在她面前的问题是,总共有多少种不同的灌注方法呢?
    注意,由于是法阵,看起来是中心对称或轴对称的两个三角形,也是实质不等同的。或者说,假如两个方案A 和B,只有通过旋转、翻转或二者组合才能使所有相同位置的三角形被灌注的元素相同,A 和B 仍然是不同的方案。只有本来所有相同位置的三角形被灌注的元素相同才算是相同的方案。
    由于方法数会很大,帕秋莉只需要你输出模1,000,000,007(10^9 + 7) 的结果就可以了。

#Input
输入文件magic.in
一共一行两个整数n,k,意义如题中所述。

#Output
输出文件magic.out。
一共一行一个整数res,表示灌注方案数模1,000,000,007(109 + 7) 得到的结果。

#Sample Input
输入1:
0 0
输入2:
0 1
输入3:
0 2
输入4:
1 1

#Sample Output
输出1:
1
输出2:
8
输出3:
32
输出4:
32

#Data Constraint
对于15% 的数据,k <= 1。
对于30% 的数据,k <= 2。
另外,有15% 的数据,满足n <= 2。
对于100% 的数据,0<= n <= 200,0<= k <= min(200, 8n + 4)。

#题解
我这个语文渣都读懂了的题,就不写题意了吧。

首先,我们发现这题是一道很明显的DP
然后,我们发现不可做。
最后,我们弃疗了。

别急,老中医还没来呢!你的心脑方不要了吗?

当然,直接放弃是不对的,我们不可能直接做出一道未给任何思路的题。
除非你抄标
废话结束。
那么我们就来从n=0的情况中找思路。
我们画一个不优美的图,来介绍各种染色情况对答案的贡献:
这里写图片描述
那么我们发现总共有10种情况来对于n=0时的计算。

那如果要放大?n=1、2、3、200?
那么我们还是从小的看起来:
n=1
这里写图片描述
我们把三角形分成3个等级:
1)红色,定义为这个三角形顶点为原点,也就是可拓展的三角形。
2)绿色,定义为边长为1的三角形
3)黄色,定义为两个2级三角形拼成的三角形。

为什么?
我们要往外拓展一层,那么不管内部结构,于是只有这三种等级。
定义这3个等级的三角形有什么用?
当然是计算啦。
怎么保证?
我们在计算方案数时要保证不能重复选择,而这三种三角形之间是会相互影响的。
怎么办?
当我们忽略内部结构,只考虑能够继续扩展的三种三角形组成的形状。我们发现,这些可以拓展的三角形一定与上面 10 种方案中的某一种同构!
是不是很神奇?
这表明,只要用方案的编号,就能将能继续扩展的三角形的集合描述出来了。
f[i][j][k] 表示到第 i 层,总共选取了 j 个三角形,能继续扩展的源三角形组成的形状的编号为k时选取三角形的方案数。
然后我们再打表记录方案数,有:
1)变化方案flag[i][j]
2)三角形三的个数d1[i]
3)三角形二的个数d2[i]
然后根据下列的决策来枚举——

  1. 枚举将哪些能够扩展的三角形向外扩展。
  2. 在之前的基础上,枚举选取几个三级三角形。
  3. 在之前的基础上,枚举选取几个二级三角形。

设s2为下一个状态,s1为当前状态。考虑递推,然后我们可以推出步骤:
变化方案 * 三角形三的个数的方案 * 三角形二的个数的方案 * 原来的方案
也就是下面的方程:
f[i+1][j+k+l][s2]+=f[i][j][s1]∗flag[s1][s2]∗C(d2[s2],k)∗C(d1[s2]−k∗2,l)f[i+1][j+k+l][s2]+=f[i][j][s1]∗flag[s1][s2]∗C(d2[s2],k)∗C(d1[s2]−k∗2,l)
(自GMH的方程)
我绝对不告诉你我懒得打。

然后就是注意边界条件。
然后就是初始化。(自己分析图片即可得到)
然后就是细节。(尤其是mo数,我不小心打成1000000009,还无伤大雅地调了半个小时)
然后就是提交AC。

标程:

var
        i,j,k,l,x,y,n,m:longint;
        flag:array [1..10,1..10] of longint=
                                        ((1,0,0,0,0,0,0,0,0,0),
                                         (1,1,0,0,0,0,0,0,0,0),
                                         (1,0,1,0,0,0,0,0,0,0),
                                         (1,2,0,1,0,0,0,0,0,0),
                                         (1,2,0,0,1,0,0,0,0,0),
                                         (1,1,1,0,0,1,0,0,0,0),
                                         (1,0,2,0,0,0,1,0,0,0),
                                         (1,3,0,2,1,0,0,1,0,0),
                                         (1,2,1,1,0,2,0,0,1,0),
                                         (1,4,0,4,2,0,0,4,0,1));
        d1:array[1..10] of longint=(12,9,6,6,6,3,0,3,0,0);
        d2:array[1..10] of longint=(4,2,1,1,0,0,0,0,0,0);
        f:array[0..200,0..200,1..10] of int64;
        c:array[0..20,0..20] of int64;
        ans,mo:int64;
begin
        assign(input,'magic.in');reset(input);
        assign(output,'magic.out');rewrite(output);
        readln(n,m);
        mo:=1000000007;
        f[0,0,1]:=1;
        f[0,1,2]:=4;
        f[0,1,3]:=4;
        f[0,2,4]:=4;
        f[0,2,5]:=2;
        f[0,2,6]:=8;
        f[0,2,7]:=2;
        f[0,3,8]:=4;
        f[0,3,9]:=4;
        f[0,4,10]:=1;
        c[0,0]:=1;
        for i:=1 to 20 do
        begin
                c[i,0]:=1;
                c[i,i]:=1;
                c[i,1]:=i;
                for j:=2 to i-1 do
                begin
                        c[i,j]:=(c[i-1,j-1]+c[i-1,j]) mod mo;
                end;
        end;
        for i:=0 to n-1 do
        begin
                for j:=0 to m do
                begin
                        for k:=1 to 10 do
                        begin
                                for l:=1 to 10 do
                                begin
                                        if (f[i,j,k]>0) and (flag[k,l]>0)  then
                                        begin
                                                for x:=0 to d2[l] do
                                                begin
                                                        for y:=0 to d1[l]-x*2 do
                                                        begin
                                                                if j+x+y<=m then
                                                                begin
                                                                        f[i+1,j+x+y,l]:=(f[i+1,j+x+y,l]+f[i,j,k]*flag[k,l]*c[d2[l],x]*c[d1[l]-x*2,y]) mod mo;
                                                                end;
                                                        end;
                                                end;
                                        end;
                                end;
                        end;
                end;
        end;
        for k:=1 to 10 do
        begin
                ans:=(ans+f[n,m,k]) mod mo;
        end;
        for i:=1 to m do ans:=(ans*i) mod mo;
        writeln(ans);
end.

转载于:https://www.cnblogs.com/RainbowCrown/p/11148409.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值