[数论][DP]魔法阵

题目描述

帕秋莉·诺蕾姬,有着“不动的大图书馆” 的称号,擅长使用各种各样的属性魔法。
——《东方求闻史记》
一如既往地,帕秋莉在图书馆中研究着魔法。今天,她在研究一本魔法书中的法阵。
这个法阵可以看成是按下面的规则生成一个规模为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,-2^i),(2^i, 0), (-2^i, 0) 为顶点,另一个以(-2^i-1,-2^i-1),(-2^i-1,2^i-1), (2^i-1,-2^i-1)(2^i-1,2^i-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)。

分析

这题是真的奇妙
这题就是求不同构的方案数
我们定义三种三角形:
1、源三角形:三点中有一点是原点(0,0)
2、一级三角形:不包含任何其他三角形且不是源三角形的三角形
3、二级三角形:由两个不重叠的一级三角形拼接成的三角形
然后对于n=0的情况,我们有这些:
这里写图片描述
然后再看其他n!=0的图形,容易发现隐去内部结构以后,都可以转换为n=0的情况,即所有图形的最大源三角形方案数都是10个
然后我们再发现:对于n到n+1的转移,源三角形向外扩张不可能多于n的时候(否则重复计算或不合法)
那么我们考虑某一个源三角形方案转换成其他源三角形的方案数量,预处理好
然后我们再预处理出当你使用某源三角形方案时,一级三角形的最多个数和二级三角形的最多个数
状态转移方程显而易见(别打我)

f [ i + 1 ] [ j + l v 1 j + l v 2 j ] [ l ] = ( f [ i + 1 ] [ j + l v 1 j + l v 2 j ] [ l ] + f [ i ] [ j ] [ k ] × t o [ k ] [ l ] × C l v 1 j t 1 × C l v 2 j t 2 ) mod 10 9 + 7

然后颜色本身在三角形中排列的方式是 P k ,即最终答案为:
k ! × i = 0 9 f [ n ] [ k ] [ 0 ]

#include <iostream>
#include <cstdio>
#define rep(i,a,b) for (i=a;i<=b;i++)
using namespace std;
typedef long long ll;
const ll MOD=1e9+7;
int n,K;
ll f[201][801][10],c[13][13],ans;
ll to[10][10]={
{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,1,1,0,1,0,0,0,0,0},
{1,0,2,0,0,1,0,0,0,0},
{1,2,0,0,0,0,1,0,0,0},
{1,2,1,1,2,0,0,1,0,0},
{1,3,0,2,0,0,1,0,1,0},
{1,4,0,4,0,0,2,0,4,1}};
ll tr1[10]={12,9,6,6,3,0,6,0,3,0},tr2[10]={4,2,1,1,0,0,0,0,0,0};
int main() {
/*  freopen("magic.in","r",stdin);
    freopen("magic.out","w",stdout);*/
    int i,j,k,l,o,p;
    scanf("%d%d",&n,&K);
    c[0][0]=1;
    rep(i,1,12)
    {
        c[i][0]=1;
        rep(j,1,i)
        c[i][j]=(c[i-1][j]+c[i-1][j-1])%MOD;
    }
    f[0][0][0]=1;
    f[0][1][1]=f[0][1][2]=4;
    f[0][2][3]=4;f[0][2][4]=8;f[0][2][5]=f[0][2][6]=2;
    f[0][3][7]=f[0][3][8]=4;
    f[0][4][9]=1;
    rep(i,0,n-1)
    rep(j,0,K)
    rep(l,0,9)
    if (f[i][j][l])
    rep(k,0,9)
    if (to[l][k]) {
        ll t1=tr1[k],t2=tr2[k];
        rep(o,0,t2)
        if (K-j-o>=0)
        {
            rep(p,0,t1-2*o)
            if (K-j-o-p>=0)
            f[i+1][j+o+p][k]=(f[i+1][j+o+p][k]+f[i][j][l]%MOD*to[l][k]%MOD%MOD*c[t2][o]%MOD*c[t1-2*o][p]%MOD)%MOD;
            else break;
        }
        else break;
    }
    rep(j,0,9) ans=(ans+f[n][K][j])%MOD;
    rep(j,1,K) ans=ans*j%MOD;
    printf("%lld",ans);
}

猜你喜欢

转载自blog.csdn.net/ssl_qyh0ice/article/details/81021692