jzoj4271. 【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,-2^i),(2^i, 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 时的法阵是这样的:
jzoj4271. 【NOIP2015模拟10.27】魔法阵_第1张图片
当n = 2 时的法阵是这样的:
jzoj4271. 【NOIP2015模拟10.27】魔法阵_第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)。

帕秋莉♂Go

15~60%

不会

100%

考虑dp。
一层层来考虑,假设当前的n是0–>1
jzoj4271. 【NOIP2015模拟10.27】魔法阵_第3张图片

设连接原点的三角形为源三角形
那么每扩张一次,就可以有如下选择(只考虑新扩张的三角形):
①把源三角形扩张一格
②选单独一个三角形(三角1)
③选两个三角形拼成的三角形(三角2)
jzoj4271. 【NOIP2015模拟10.27】魔法阵_第4张图片

因为源三角形的状态有限,所以考虑把源三角形设为一维
那么设状态f[i][j][s],表示当前到第i层,选了j个三角形,当前源三角形的状态为s
可以得出s一共有10种情况(数字表示重构个数):
jzoj4271. 【NOIP2015模拟10.27】魔法阵_第5张图片

于是一共就10种情况,各种变化可以先打个表预处理
先处理好状态之间的变化方案flag[i][j]
还有状态i时三角1、2的个数d1[i]、d2[i]
(这些情况没有考虑颜色,所以最后的答案要乘上m!)

那么每次枚举一个状态f[i][j][s1],枚举下一位的状态s2
然后枚举三角2的个数k,这样可以很方便地枚举三角1的个数l

于是方程就很显然了:
f[i+1][j+k+l][s2]+=f[i][j][s1]flag[s1][s2]C(d2[s2],k)C(d1[s2]k2,l) f [ i + 1 ] [ j + k + l ] [ s 2 ] + = f [ i ] [ j ] [ s 1 ] ∗ f l a g [ s 1 ] [ s 2 ] ∗ C ( d 2 [ s 2 ] , k ) ∗ C ( d 1 [ s 2 ] − k ∗ 2 , l )
(感谢CZC的提醒)
就是当前方案转换的方案数三角2的方案*三角1的方案
组合数可以预处理,还要考虑不要超出边界

初始化(由图得):

f[0][0][0]=1;
f[0][1][1]=4;
f[0][1][2]=4;
f[0][2][3]=4;
f[0][2][4]=2;
f[0][2][5]=8;
f[0][2][6]=2;
f[0][3][7]=4;
f[0][3][8]=4;
f[0][4][9]=1;

最后统计一下答案就行了

code

#include 
#include 
#include 
#define fo(a,b,c) for (a=b; a<=c; a++)
#define fd(a,b,c) for (a=b; a>=c; a--)
#define mod 1000000007
#define max(a,b) (a>b?a:b)
#define min(a,b) (a
using namespace std;

int flag[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 ,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[10]={12,9,6,6,6,3,0,3,0,0}
 ,d2[10]={4 ,2,1,1,0,0,0,0,0,0};

int f[201][201][10];
int C[13][13];
int n,m,i,j,k,l,s1,s2;
long long ans;

int main()
{
    freopen("magic.in","r",stdin);
    freopen("magic.out","w",stdout);

    f[0][0][0]=1;
    f[0][1][1]=4;
    f[0][1][2]=4;
    f[0][2][3]=4;
    f[0][2][4]=2;
    f[0][2][5]=8;
    f[0][2][6]=2;
    f[0][3][7]=4;
    f[0][3][8]=4;
    f[0][4][9]=1;

    C[0][0]=1;
    fo(i,1,12)
    {
        C[i][0]=1;
        C[i][1]=i;
        C[i][i]=1;

        fo(j,2,i-1)
        C[i][j]=(C[i-1][j-1]+C[i-1][j])%mod;
    }

    scanf("%d%d",&n,&m);

    fo(i,0,n-1)
    {
        fo(j,0,m)
        {
            fo(s1,0,9)
            if (f[i][j][s1])
            {
                fo(s2,0,9)
                if (flag[s1][s2])
                {
                    fo(k,0,d2[s2])
                    {
                        fo(l,0,d1[s2]-k*2)
                        if (j+k+l<=m)
                        f[i+1][j+k+l][s2]=(f[i+1][j+k+l][s2]+(long long) f[i][j][s1]*flag[s1][s2]%mod*C[d2[s2]][k]%mod *C[d1[s2]-k*2][l]%mod)%mod;
                    }
                }
            }
        }
    }

//  i=n j=m
    ans=0;
    fo(s1,0,9)
    ans=(ans+f[n][m][s1])%mod;
    fo(i,1,m)
    ans=ans*i%mod;

    printf("%lld\n",ans);

    fclose(stdin);
    fclose(stdout);

    return 0;
}

你可能感兴趣的:(OJ题解,DP)