很久没有写题解了~因为懒(年纪大了就是脸皮厚,还有脸说)

这道题今天花了很长时间去推,一开始以为是规律题,没推出来,直接模拟也TLE了,接着考虑实在是没思路,看了题解。

思路大概就是这样:

先上代码(别人大佬的)

#include<iostream>
using namespace std;

int main()
{
    int n;
    int a[305];
    memset(a, 0, sizeof(a));
    a[0] = a[1] = 1;
    int i, j;
    for (i = 3; i < 305; i += 2)    //基数是共轭的
    {


        for (j = 305 - i; j >= 0; j--)
        {
            a[i + j] += a[j];  //基数加偶数还是基数,所以共轭,基数加基数是偶数,还是共轭的
        }
    }
    while (cin >> n)
    {
        cout << a[n] << endl;
    }
    return 0;
}

其实就是一道简单的递推题,关键是思路的问题

 

我们把一个自共轭Ferrers图的最外面的横行和竖行去掉,会发现剩下来的还是自共轭Ferrers图,接着再去掉,一直到只剩下一个,OK,一个当然只有一种放置方法。

 

 

然后我们再看到   另外一个 面积为3(只有一行竖和横)的自共轭Ferrers图,会发现它还可以放1个面积在第二行,于是面积就成为了4,依然还是自共轭Ferrers图。

再再再看到一个面积为5(只有一行竖和横)的自共轭Ferrers图,会发现它还可以放1个面积,可以放3个面积,可以放4个面积,于是面积就成为了6,8,9,面积为6,8,9的依然还是自共轭Ferrers图。

最后再看到一个面积为9(只有一行竖和横)的自共轭Ferrers图,会发现它还可以放1个,4个,5个等等。

 

这样子思路就出来了:

我们由大到小开始遍历看看能在自己里面放几个,放完组成的面积是多少,该对应面积的排列数加一

 

例如 

首先 我们给a[0],a[1]赋值1,因为面积1和0就只有1种了,其他a[]都为0

然后我们从大到小开始遍历

第一次有效赋值是从a[3+1]+=a[1]开始的,这表示着  面积3添加1个面积,得到面积4,面积4就可以由3+1这种组合得到,于是加上面积1的组合数就等于面积4的总组合数

第二次有校赋值a[3+0]+=a[0],这表示着  面积3添加0个面积,得到面积3,面积3就可以由3+0这种组合得到,于是加上面积0的组合数就等于面积3的总组合数

再看看a[8]的组合方式   5+3,7+1,所以面积8的组合数就是面积3的组合数+面积1的组合数。

最后看看a[18]的组合方式,9+5+3+1,所以面积18的组合数为4.

 

 

下面再说说代码上的解释

第一个for循环之所以+=2,是因为是在横竖两边各加了一个单位

第二个for循环之所以是从大到小遍历,是因为我们更新的数据要从小开始,因为我们添加的单位不能超过边界,也就是以最外界横竖为长宽的边界。

例如a[3+100]+=a[100],这样其实是无效的,因为a[100]此时仍为0

而a[3+1]+=a[1],这样则是有校的,因为a[1]此时为1,也就代表着,面积3可以放得下面积1从而构成面积4.

还有一个好处就是 例如a[18]==4 如果是a[81+18]==a[99],这样意味着a[81]的面积添加a[18]的所有组合数了,因为a[18]不仅仅只有一种组合数.