这道题好无语呀,500ms时限,60m的内存。
如果没有内存限制,我们可以很容易的想到 DP[U][V][ROW][KNIGHT] U 代表上一行的状态,V代表上上一行的状态。因为当前行只与前两行的状态有关。ROW代表行数,knight代表骑士数目。
然后dp就很简单了 DP【U】【V】【ROW】【KNIGHT】 = SUM(DP【V】【i】【ROW-1]【KNIGHT-CNT(i)】 ) i代表枚举的当前行的可行的状态(状态用一个整数表示),cnt(i) 就是求出状态i出现了多少个骑士
可是这样开出的dp 就应该 是 DP【1024]【1024]【10]【101】,显然超出内存了。
所以需要压缩,将前两行并成一个数。这样使得两行没冲突的合法状态最多又28000多个。然后 dp可以写成DP【29000】【10]【101】可是这样还是超出内存 ,然后在这里用滚动数组就ok了。由于我用的记忆化搜,写法不优越,10和9都不能很快出解。所以干脆打了个表。打出10 和 9的表之后 使得强两行无冲突的状态大大减少 DP应该是DP【10000】【10】【101】这个大小。
跪求优越的写法呀~~~
#include <stdio.h>
#include <iostream>
#include <string.h>
#include <cmath>
#include <vector>
#include <set>
#include <map>
#include <algorithm>
#include <string>
using namespace std;
typedef pair<int,int> pii;
typedef long long ll;
typedef double dl;
typedef vector<pii> vii;
typedef set<pii> sii;
/*sim_operarion*/
#define sfint(x) scanf("%d",&x)
#define sfint2(x,y) scanf("%d%d",&x,&y)
#define sfint3(x,y,z) scanf("%d%d%d",&x,&y,&z)
#define sfstr(c) scanf("%s",c)
#define sfdl(x) scanf("%lf",&x)
#define pfint(x) printf("%d\n",x)
#define fr(i,s,n) for(int i=s;i<n;++i)
#define _fr(i,n,s) for(int i=n-1;i>=s;--i)
#define cl(a) memset(a,0,sizeof(a))
int n,k;
ll dp[10820][11][51];
int canuse[11000];
int tot;
int hash[1024*1024+1];
int cnt[1025];
ll list_10[110]={
1,100,4662,135040,2732909,41199404,481719518,4491423916,34075586550,213628255072,1120204619108,4961681221524,18715619717199,60541371615660,168976761361446,409191804533576,864172675710439,1599730843649564,2609262108838924,3770687313420780,4857550050070531,5616928666465104,5874943705896600,5604501518609804,4917655076255841,3999855946779732,3034690618677388,2156485957257040,1437827591264317,899278231344296,526753407546620,288274613750624,146990556682887,69626509814580,30542906352994,12366448408056,4604442057431,1569983914256,487876545370,137395261280,34831261750,7884855000,1578162590,275861904,41455966,5246412,543534,44244,2652,104,2
};
ll list_9[82]={
1,81,3016,68796,1080942,12472084,110018552,762775440,4241252429,19206532478,71707869632,222946143752,582155146204,1286247689414,2421159140764,3908273840366,5446391581062,6599640204257,7010436668992,6589213734278,5537849837497,4207779106033,2920161348852,1865346129716,1101125592067,600730512987,302041066250,139345014744,58692638521,22451454400,7755194754,2403337080,663103709,161373907,34237130,6238414,957145,120334,11914,872,42,1
};
int hashed(int x,int y) {
return x*1024+y;
}
int lim;
int count(int x) {
int ret = 0;
fr(i , 0 ,n) if (1<<i & x) ++ret;
return ret;
}
void init() {
tot = 0;
fr(i , 0 ,lim) {
fr(j , 0 ,lim) {
if (!(j<<2 & i || j>>2&i)) {
int tmp = hashed(i,j);
hash[tmp] = tot;
canuse[tot++] = tmp;
}
}
}
fr(i , 0 ,lim) cnt[i] = count(i);
}
ll dfs(int u,int row,int knight) {
if (dp[u][row][knight]!=-1) return dp[u][row][knight];
int x=canuse[u]/1024,y=canuse[u]%1024;
dp[u][row][knight] = 0;
fr( i , 0 ,lim) {
if (knight>=cnt[i]) {
if (!(i<<1 & x || i>>1&x || i<<2&y ||i>>2&y)) {
if (row == 1) if (cnt[i]==knight) dp[u][row][knight]++;
else dp[u][row][knight] += dfs(hash[i+y*1024],row-1,knight-cnt[i]);
}
}
}
return dp[u][row][knight];
}
int main() {
while(cin>>n>>k) {
lim = 1<<n;
if (n == 10) {
cout<<list_10[k]<<endl;
continue;
}
if (n==9){
cout<<list_9[k]<<endl;
continue;
}
init();
memset(dp,-1,sizeof(dp));
ll ans = dfs(0,n,k);
cout<<ans<<endl;
}
return 0;
}