sgu220&sgu221 分类: sgu 2015-06-15 22:01 24人阅读 评论(0) 收藏


首先按横纵坐标之和的奇偶性对棋盘染色,
可以发现染色不同的方格之间是不会互相影响的。


把棋盘旋转 45°,就会得到一个菱形方格图,
只考虑白色方格上的棋子,原本是沿对角线移动,
但此时它们沿水平方向和竖直方向移动。


注意到菱形方格图中每行的方格数不全相同,
所以按方格数从小到大的先后顺序处理行,以避免后效性。

fi,j 表示前 i 行,用 j 个棋子的方案数,
fi,j=fi1,j+fi1,j1(cntij+1) | cnti>=j

复杂度:O(nk)


#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<algorithm>

const int sz = 11;

int n, k, c[2];
long long f[2][sz][sz*sz];
long long ans;
int lcnt[sz<<1];

int linecnt(int t)
{
    return (t<=n)?t:((n<<1)-t);
}

void solve(int x)
{
    f[x][0][0] = 1;

    for(int i = 1; ((i<<1)-x) <= (n<<1); c[x] = i++)
        lcnt[i] = linecnt((i<<1)-x);
    std::sort(lcnt + 1, lcnt + c[x] + 1);   

    for(int i = 1; i <= c[x]; i++)
        for(int j = 0; j <= k && j <= lcnt[i]; j++)
            f[x][i][j] = f[x][i-1][j] + f[x][i-1][j-1]*(lcnt[i]-j+1);   

}
void getans()
{
    for(int i = 0; i <= k; i++)
        ans += f[0][c[0]][i]*f[1][c[1]][k-i];
}

int main()
{
#ifndef ONLINE_JUDGE    
    freopen("sgu220.in","r",stdin);
    freopen("sgu220.out","w",stdout);
#endif

    std::cin >> n >> k;

    solve(0), solve(1), getans();

    std::cout << ans;

#ifndef ONLINE_JUDGE
    fclose(stdin);
    fclose(stdout); 
#endif
    return 0;   
}

#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<algorithm>

const int sz = 51, Base = 10000;

struct BigNum
{
    int num[sz], l;
}emp;

int n, k;
BigNum f[2][sz][sz*sz];
BigNum ans;

int c[2], lcnt[sz<<1];

void digit(int &plus,int &tp)
{
    plus += tp/Base, tp %= Base;
}
BigNum operator *(const BigNum &a,const int &b)
{
    BigNum ret = a;

    if(!a.l || !b){ret.l = 0; return ret;}

    for(int i = 1; i <= ret.l; i++) ret.num[i] = a.num[i] * b;
    for(int i = 1; i <= ret.l; i++) digit(ret.num[i+1] ,ret.num[i]);
    while(ret.num[ret.l+1]) ++ret.l, digit(ret.num[ret.l+1], ret.num[ret.l]);   
    return ret;     
}
BigNum operator +(const BigNum &a,const BigNum &b)
{
    BigNum ret = emp;   ret.l = std::max(a.l,b.l);
    for(int i = 1; i <= ret.l; i++) ret.num[i] = a.num[i] + b.num[i];
    for(int i = 1; i <= ret.l; i++) digit(ret.num[i+1] ,ret.num[i]);
    if(ret.num[ret.l+1]) ret.l++;   
    return ret;     
}
BigNum operator *(const BigNum &a,const BigNum &b)
{
    BigNum ret = emp;   

    if(!a.l || !b.l){ret.l = 0; return ret;}

    ret.l = a.l + b.l - 1;      

    for(int i = 1; i <= a.l; i++)
        for(int j = 1; j <= b.l; j++)
        {
            ret.num[i+j-1] += a.num[i]*b.num[j];
            digit(ret.num[i+1], ret.num[i]);
        }

    for(int i = 1; i <= ret.l; i++) digit(ret.num[i+1] ,ret.num[i]);
    while(ret.num[ret.l+1]) ++ret.l, digit(ret.num[ret.l+1], ret.num[ret.l]);   

    return ret;     
}
void prt(const BigNum &a)
{
    printf("%d",a.num[a.l]);
    for(int i = a.l-1; i >= 1; i--)
        printf("%04d",a.num[i]);
}

int linecnt(int t)
{
    return (t<=n)?t:((n<<1)-t);
}
void solve(int x)
{
    f[x][0][0].l = f[x][0][0].num[1] = 1;

    for(int i = 1; ((i<<1)-x) <= (n<<1); c[x] = i++)
        lcnt[i] = linecnt((i<<1)-x);
    std::sort(lcnt + 1, lcnt + c[x] + 1);   

    for(int i = 1; i <= c[x]; i++)
        for(int j = 0; j <= k && j <= lcnt[i]; j++)
            f[x][i][j] = f[x][i-1][j] + (f[x][i-1][j-1]*(lcnt[i]-j+1)); 

}
void getans()
{
    for(int i = 0; i <= k; i++)
        ans = ans + (f[0][c[0]][i]*f[1][c[1]][k-i]);
}

int main()
{
#ifndef ONLINE_JUDGE    
    freopen("sgu221.in","r",stdin);
    freopen("sgu221.out","w",stdout);
#endif

    std::cin >> n >> k;

    solve(0), solve(1), getans();

    prt(ans);

#ifndef ONLINE_JUDGE
    fclose(stdin);
    fclose(stdout); 
#endif
    return 0;   
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

posted @ 2015-06-15 22:01  <Dash>  阅读(119)  评论(0编辑  收藏  举报