2010年1月18日星期一.sgu220 sgu221 n*n的棋盘上放k个象
2010年1月18日星期一.sgu220 sgu221sgu220:n*n的棋盘上放k个象 (n <= 10)
终究还不全是自己想出来的,看到一个提示,放在黑格和白格上的象互不相关。
然后我就开始想状态压缩dp。。。
注意到
+ + + +
+ + +
+ + + +
+ + +
+ + + +
+ + +
+ + + +
如果想对+上边放车的情况进行dp,可以把黑格变成这样:
+
+
+++
+++
+++++
+++++
+++++++
然后就可以使用放车的方法进行二维dp了。
可惜老夫想歪了,虽然也过了,但是是状态压缩的,只能对于这题有用,对sgu221就不行了.
状态压缩见代码:
int c[bin(N)],bsp,wsp;
LL black[N],white[N];
LL dpblack[N][N][bin(N)], cb[N];
LL dpwhite[N][N][bin(N)], cw[N];
// http://www.cppblog.com/schindlerlee
void preproc()
{
int i;
full = bin(n) - 1 ;
bsp = wsp = 1 ;
for (i = 1 ; i < n; i += 2 ) {
black[bsp ++ ] = rev(bin(i) - 1 ) & full;
black[bsp ++ ] = rev(bin(i) - 1 ) & full;
}
if (i == n) { black[bsp ++ ] = rev(bin(i) - 1 ) & full; }
for (i = 2 ; i < n; i += 2 ) {
white[wsp ++ ] = rev(bin(i) - 1 ) & full;
white[wsp ++ ] = rev(bin(i) - 1 ) & full;
}
if (i == n) { white[wsp ++ ] = rev(bin(i) - 1 ) & full; }
for (i = 1 ;i <= full;i ++ ) {
int t = i;
while (t > 0 ) {
c[i] += t & 1 ;
t >>= 1 ;
}
}
}
void proc(LL dp[N][N][bin(N)], int terrain[N], int sp,LL res[N])
{
int i, line, s;
dp[ 0 ][ 0 ][ 0 ] = 1 ;
for (line = 1 ; line <= sp; line ++ ) {
for (s = 0 ; s <= full; s ++ ) { dp[line][c[s]][s] += dp[line - 1 ][c[s]][s]; }
for (i = 1 ; i <= full; i <<= 1 ) {
if (i & terrain[line]) continue ;
for (s = 0 ; s <= full; s ++ ) {
if (i & s) continue ;
dp[line][c[i | s]][i | s] += dp[line - 1 ][c[s]][s];
}
}
}
for (i = 0 ;i <= k && i <= sp;i ++ ) {
for (s = 0 ;s <= full;s ++ ) {
res[i] += dp[sp][i][s];
}
}
}
int main()
{
int i;
scanf( " %d%d " , & n, & k);
preproc();
proc(dpblack, black, bsp - 1 , cb);
proc(dpwhite, white, wsp - 1 , cw);
LL res = 0 ;
for (i = 0 ;i <= k;i ++ ) {
if (i < bsp && k - i < wsp) // really important
res += cb[i] * cw[k - i];
}
cout << res << endl;
return 0 ;
}
其实可以发现
如果f(i,j)表示前i行放j个
那么f[i][j] = f[i-1][j] + f[i-1][j-1] * (n(i) - (j-1))
然后程序就变成了这个样子。。
const int N = 101 ;
LL fb[N][N],fw[N][N];
LL black[N],white[N];
int wsp,bsp,n,k;
void preproc()
{
int i;
bsp = wsp = 1 ;
for (i = 1 ; i < n; i += 2 ) {
black[bsp ++ ] = i;
black[bsp ++ ] = i;
}
if (i == n) { black[bsp ++ ] = i; }
for (i = 2 ; i < n; i += 2 ) {
white[wsp ++ ] = i;
white[wsp ++ ] = i;
}
if (i == n) { white[wsp ++ ] = i; }
bsp -- ,wsp -- ;
}
void proc(LL dp[N][N],LL terrain[N], int sp)
{
int i,j;
dp[ 0 ][ 0 ] = 1 ;
for (i = 1 ;i <= sp;i ++ ) {
for (j = 0 ;j <= terrain[i];j ++ ) {
dp[i][j] = dp[i - 1 ][j] + dp[i - 1 ][j - 1 ] * (terrain[i] - j + 1 );
}
}
}
int main()
{
int i;
scanf( " %d%d " , & n, & k);
preproc();
proc(fb,black,bsp);
proc(fw,white,wsp);
LL res = 0 ;
for (i = 0 ;i <= k;i ++ ) {
res += fb[bsp][i] * fw[wsp][k - i];
}
cout << res << endl;
return 0 ;
}
sgu221:n*n的棋盘上放k个象 (n <= 50)
这题由于数据量变大了,所以需要高精度的模板,本人是上的java
//http://www.cppblog.com/schindlerlee/
public class Solution {
static int black[], white[];
static int wsp, bsp, n, k;
static void preproc() {
int i;
bsp = wsp = 1 ;
for (i = 1 ; i < n; i += 2 ) {
black[bsp ++ ] = i;
black[bsp ++ ] = i;
}
if (i == n) {
black[bsp ++ ] = i;
}
for (i = 2 ; i < n; i += 2 ) {
white[wsp ++ ] = i;
white[wsp ++ ] = i;
}
if (i == n) {
white[wsp ++ ] = i;
}
bsp -- ;
wsp -- ;
}
public static void main(String[] args) {
Scanner cin = new Scanner(
new BufferedReader(
new InputStreamReader(System.in)));
int i, j;
n = cin.nextInt();
k = cin.nextInt();
if (k >= n * 2 ) {
System.out.println( " 0 " );
return ;
}
black = new int [ 456 ];
white = new int [ 456 ];
BigInteger[][] fb = new BigInteger[ 456 ][ 456 ];
BigInteger[][] fw = new BigInteger[ 456 ][ 456 ];
preproc();
for (i = 0 ; i < 456 ; i ++ ) {
for (j = 0 ; j < 456 ; j ++ ) {
fb[i][j] = BigInteger.ZERO;
fw[i][j] = BigInteger.ZERO;
}
}
fb[ 0 ][ 0 ] = BigInteger.ONE;
for (i = 1 ; i <= bsp; i ++ ) {
fb[i][ 0 ] = BigInteger.ONE;
for (j = 1 ; j <= black[i]; j ++ ) {
BigInteger tmp = BigInteger.valueOf(black[i] - j + 1 );
fb[i][j] = fb[i - 1 ][j].add(fb[i - 1 ][j - 1 ].multiply(tmp));
}
}
fw[ 0 ][ 0 ] = BigInteger.ONE;
for (i = 1 ; i <= wsp; i ++ ) {
fw[i][ 0 ] = BigInteger.ONE;
for (j = 1 ; j <= white[i]; j ++ ) {
BigInteger tmp = BigInteger.valueOf(white[i] - j + 1 );
fw[i][j] = fw[i - 1 ][j].add(fw[i - 1 ][j - 1 ].multiply(tmp));
}
}
BigInteger res = BigInteger.ZERO;
for (i = 0 ; i <= k; i ++ ) {
res = res.add(fb[bsp][i].multiply(fw[wsp][k - i]));
}
System.out.println(res);
}
}
public class Solution {
static int black[], white[];
static int wsp, bsp, n, k;
static void preproc() {
int i;
bsp = wsp = 1 ;
for (i = 1 ; i < n; i += 2 ) {
black[bsp ++ ] = i;
black[bsp ++ ] = i;
}
if (i == n) {
black[bsp ++ ] = i;
}
for (i = 2 ; i < n; i += 2 ) {
white[wsp ++ ] = i;
white[wsp ++ ] = i;
}
if (i == n) {
white[wsp ++ ] = i;
}
bsp -- ;
wsp -- ;
}
public static void main(String[] args) {
Scanner cin = new Scanner(
new BufferedReader(
new InputStreamReader(System.in)));
int i, j;
n = cin.nextInt();
k = cin.nextInt();
if (k >= n * 2 ) {
System.out.println( " 0 " );
return ;
}
black = new int [ 456 ];
white = new int [ 456 ];
BigInteger[][] fb = new BigInteger[ 456 ][ 456 ];
BigInteger[][] fw = new BigInteger[ 456 ][ 456 ];
preproc();
for (i = 0 ; i < 456 ; i ++ ) {
for (j = 0 ; j < 456 ; j ++ ) {
fb[i][j] = BigInteger.ZERO;
fw[i][j] = BigInteger.ZERO;
}
}
fb[ 0 ][ 0 ] = BigInteger.ONE;
for (i = 1 ; i <= bsp; i ++ ) {
fb[i][ 0 ] = BigInteger.ONE;
for (j = 1 ; j <= black[i]; j ++ ) {
BigInteger tmp = BigInteger.valueOf(black[i] - j + 1 );
fb[i][j] = fb[i - 1 ][j].add(fb[i - 1 ][j - 1 ].multiply(tmp));
}
}
fw[ 0 ][ 0 ] = BigInteger.ONE;
for (i = 1 ; i <= wsp; i ++ ) {
fw[i][ 0 ] = BigInteger.ONE;
for (j = 1 ; j <= white[i]; j ++ ) {
BigInteger tmp = BigInteger.valueOf(white[i] - j + 1 );
fw[i][j] = fw[i - 1 ][j].add(fw[i - 1 ][j - 1 ].multiply(tmp));
}
}
BigInteger res = BigInteger.ZERO;
for (i = 0 ; i <= k; i ++ ) {
res = res.add(fb[bsp][i].multiply(fw[wsp][k - i]));
}
System.out.println(res);
}
}