SGU 225

      题意:给出一个n*n的棋盘和k个马,问有多少种放的方法使得马互不相攻击。

      题解:首先很容易想到设dp[u][v][i][j]表示前i行,用了j个马,第i行的状态为v,前一行的状态为u。

dp[u][v][i][j]+=dp[i][u][i-1][j-cnt[v]]且v不与i,u冲突。

  判冲突的话可以这样,前两行左移1位&当前行,为1则冲突,然后右移一样的。前一行就左右移两位&当前行

但这样做会爆空间,考虑u,v压到一个int 内,再对行数用滚动数组,再n=8,9,10打表。ps(打表调得我好苦啊);

%%%__debug。

#include<cstdlib>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<iostream>
using namespace std;
const int MAXS=1025,base=256,MAXN=11,MAXST=70000,MAXK=51;
typedef long long ll;
ll dp[MAXST][2][MAXK];
int lim,tot=0,st[MAXST],cnt[MAXST];
ll list_10[110]={1LL,100LL,4662LL,135040LL,2732909LL,41199404LL,481719518LL,4491423916LL,34075586550LL,213628255072LL,1120204619108LL,4961681221524LL,18715619717199LL,60541371615660LL,168976761361446LL,409191804533576LL,864172675710439LL,1599730843649564LL,2609262108838924LL,3770687313420780LL,4857550050070531LL,5616928666465104LL,5874943705896600LL,5604501518609804LL,4917655076255841LL,3999855946779732LL,3034690618677388LL,2156485957257040LL,1437827591264317LL,899278231344296LL,526753407546620LL,288274613750624LL,146990556682887LL,69626509814580LL,30542906352994LL,12366448408056LL,4604442057431LL,1569983914256LL,487876545370LL,137395261280LL,34831261750LL,7884855000LL,1578162590LL,275861904LL,41455966LL,5246412LL,543534LL,44244LL,2652LL,104LL,2};
ll list_9[82]={1LL,81LL,3016LL,68796LL,1080942LL,12472084LL,110018552LL,762775440LL,4241252429LL,19206532478LL,71707869632LL,222946143752LL,582155146204LL,1286247689414LL,2421159140764LL,3908273840366LL,5446391581062LL,6599640204257LL,7010436668992LL,6589213734278LL,5537849837497LL,4207779106033LL,2920161348852LL,1865346129716LL,1101125592067LL,600730512987LL,302041066250LL,139345014744LL,58692638521LL,22451454400LL,7755194754LL,2403337080LL,663103709LL,161373907LL,34237130LL,6238414LL,957145LL,120334LL,11914LL,872LL,42LL,1}; 
ll list_8[65]={1LL,64LL,1848LL,32084LL,376560LL,3184708LL,20202298LL,98796304LL,379978716LL,1167053680LL,2897726604LL,5876860140LL,9825415557LL,13660238780LL,15932672964LL,15737653004LL,13304668385LL,9742722088LL,6260518246LL,3574590840LL,1830733371LL,844203844LL,349524138LL,128874944LL,41833846LL,11792736LL,2840224LL,572432LL,93840LL,12004LL,1122LL,68LL,2LL,0LL,0LL,0LL,0LL,0LL,0LL,0LL,0LL,0LL,0LL,0LL,0LL,0LL,0LL,0LL,0LL,0LL,0LL,0LL,0LL,0LL,0LL,0LL,0LL,0LL,0LL,0LL,0LL,0LL,0LL,0LL,0LL};
int hashed(int x,int y)
{
    return x*base+y;
}
int get1(int x)
{
    int tmp=x,c=0;
    while(tmp)
    {
        if(tmp&1)c++;
        tmp>>=1;
    }
    return c;
}
void init()
{
    memset(dp,0,sizeof(dp));
    memset(cnt,0,sizeof(cnt));
    memset(st,0,sizeof(st));
    tot=0;
    for(int i=0;i<lim;i++)
       for(int j=0;j<lim;j++)
       {
            if(!((i<<2&j)||(i>>2&j)))
                st[tot++]=hashed(i,j);
        }
    for(int i=0;i<MAXST;i++)cnt[i]=get1(i);
}
void clear(int p,int& k)
{
    for(int i=0;i<MAXST;i++)
       for(int j=0;j<=k;j++)dp[i][p][j]=0;
}
ll work(int n,int k,int t)
{
    lim=1<<n;
    init();dp[0][0][0]=1;
    int p=1;
    for(int i=1;i<=n;i++)
    {
           clear(p,k); 
           for(int j=0;j<=k;j++)
           {
                for(int s=0;s<tot;s++)if(cnt[st[s]]<=k)
                {
                    if(i==1&&st[s]!=0)break;
                    if(i==2&&st[s]>=base)break;
                    for(int l=0;l<1<<n;l++)
                    {
                        int x=st[s]/base,y=st[s]%base;
                        if(!((x<<1&l)||(x>>1&l)||(y<<2&l)||(y>>2&l)))
                           if(j>=cnt[l])
                           {
                                ll tmp=dp[st[s]][p^1][j-cnt[l]];
                                dp[y*base+l][p][j]+=tmp;
                            }
                    }
                }
            }
            p^=1;
        }
        ll ans=0;
        for(int i=0;i<tot;i++)
                if(cnt[st[i]]<=k)
                    ans+=dp[st[i]][n&1][k];
        return ans;
}
int main()
{
    freopen("225.in","r",stdin);
    freopen("w.out","w",stdout);
    int n,k;
    scanf("%d %d",&n,&k);
    if(n==10)cout<<list_10[k]<<endl;
    else if(n==9)cout<<list_9[k]<<endl;
    else if(n==8)cout<<list_8[k]<<endl;
    else if(k>MAXK)cout<<0<<endl;
    else
            printf("%I64d",work(n,k,1));
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值