hdu 5180 状态压缩 dp 打表

hdu 5180 状态压缩 dp 打表
题意:
在n*n的国际象棋中,放置若干个国王和k个车,使得国王之间不互相攻击,车之间不互相攻击,车不可攻击到国王(这并不代表国王不能攻击到车)。国王能攻击到它上下左右,左上左下右上右下八个位置的棋子,车可以攻击到同一行或同一列中的棋子,求方案总数对1000000007取模后的值。 

限制:
1 <= n <=15; 0 <= k <=15

思路:
状态压缩,dp,打表套打表

/*hdu 5180
  题意:
  在n*n的国际象棋中,放置若干个国王和k个车,使得国王之间不互相攻击,车之间不互相攻击,车不可攻击到国王(这并不代表国王不能攻击到车)。国王能攻击到它上下左右,左上左下右上右下八个位置的棋子,车可以攻击到同一行或同一列中的棋子,求方案总数对1000000007取模后的值。 
  限制:
  1 <= n <=15; 0 <= k <=15
  思路:
  状态压缩,dp,打表套打表
 */
#include
    
    
     
     
#include
     
     
      
      
using namespace std;
int ans[15][16]={
	2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
	5,8,2,0,0,0,0,0,0,0,0,0,0,0,0,0,
	35,72,36,6,0,0,0,0,0,0,0,0,0,0,0,0,
	314,940,702,192,24,0,0,0,0,0,0,0,0,0,0,0,
	6427,20953,18778,6528,1200,120,0,0,0,0,0,0,0,0,0,0,
	202841,724224,766278,310368,63000,8640,720,0,0,0,0,0,0,0,0,0,
	12727570,45687569,51049098,22486656,4751400,648000,70560,5040,0,0,0,0,0,0,0,0,
	355115594,736342192,480159099,593158322,564699600,71527200,7161840,645120,40320,0,0,0,0,0,0,0,
	718817248,766062498,551790315,804772379,958725252,916206996,91739593,85155840,6531840,362880,0,0,0,0,0,0,
	789281595,29367309,234810099,689850602,160354814,575223606,565338593,166965641,87551353,72576000,3628800,0,0,0,0,0,
	245046738,212490784,527909966,404618207,648188905,539918379,532542087,165451585,428944600,878079902,878169600,39916800,0,0,0,0,
	681555006,278546674,315035573,624869750,794507062,84429000,792648481,661448548,160683200,93278547,346974481,496038323,479001600,0,0,0,
	413451720,259920010,496775457,225920769,842092390,332550368,221710589,232620660,166171087,462729811,955852083,835265947,902539673,227020758,0,0,
	571703274,654602013,270251289,900887757,942422378,974702258,610771898,46596778,844659211,467836761,298284961,960033762,424915175,992136520,178290591,0,
	7017421,361818480,635021015,633194321,924790619,16861446,556906023,606568231,432184532,717658304,181068670,990596447,108561136,862468715,230765390,674358851};
int main(){
	int T;
	int n,k;
	scanf("%d",&T);
	while(T--){
		scanf("%d%d",&n,&k);
		printf("%d\n",ans[n-1][k]);
	}
	return 0;
}

     
     
    
    


打表程序如下:
打表程序1:
tab[a][b]表示a*b的棋盘王的放置情况的种数。
由于只有15*15,所以可以用状态压缩dp来解决。

/*hdu 5180
  表1:
  tab[a][b]表示a*b的棋盘王的放置情况的种数。
  由于只有15*15,所以可以用状态压缩dp来解决。
 */
#include
    
    
     
     
#include
     
     
      
      
#include
      
      
       
       
using namespace std;
#define LL __int64
const int MOD=1000000007;
LL dp[20][1<<16];
int a[1<<16],cnt;
int tab[20][20];
int main(){
	for(int i=1;i<=15;++i){
		cnt=0;
		for(int j=0;j<(1<
       
       
        
        >1))) continue;

					dp[j][a[k]]=(dp[j][a[k]]+dp[j-1][a[l]])%MOD;
				}
				sum=(sum+dp[j][a[k]])%MOD;
			}
			tab[j+1][i]=sum;
		}
	}
	for(int i=0;i<=15;++i){
		for(int j=0;j<=15;++j)
			cout<
        
        
          <<','; cout< 
          
        
       
       
      
      
     
     
    
    


打表程序2:
基于表1然后打出表2,
表2是答案表。
因为问题只有15*16,对于每种情况:(n,k),先之间考虑k辆车的情况,可以用两个二进制数表示k辆车在棋盘上的分布,然后可以发现车的本质是把棋盘分割成若干部分,每部分的王的放置情况在表1中已经打出,剩下的部分可以很容易算出来。

ps:这个程序一定要好好优化,不然要打好长时间,我的大概要跑10min左右。

/*hdu 5180
  表2:
  基于表1然后打出表2,
  表2是答案表。
  因为问题只有15*16,对于每种情况:(n,k),先之间考虑k辆车的情况,可以用两个二进制数表示k辆车在棋盘上的分布,然后可以发现车的本质是把棋盘分割成若干部分,每部分的王的放置情况在表1中已经打出,剩下的部分可以很容易算出来。
 */
#include
     
     
      
      
#include
      
      
       
       
#include
       
       
#include
        
        
         
         
using namespace std;
#define LL __int64
const int MOD=1000000007;
int a[1<<16],cnt;
int tab[16][16]={
	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
	0,2,3,5,8,13,21,34,55,89,144,233,377,610,987,1597,
	0,3,5,11,21,43,85,171,341,683,1365,2731,5461,10923,21845,43691,
	0,5,11,35,93,269,747,2115,5933,16717,47003,132291,372157,1047181,2946251,8289731,
	0,8,21,93,314,1213,4375,16334,59925,221799,817280,3018301,11134189,41096528,151643937,559640289,
	0,13,43,269,1213,6427,31387,159651,795611,4005785,20064827,100764343,505375405,536323131,724854929,851706016,
	0,21,85,747,4375,31387,202841,1382259,9167119,61643709,411595537,758179825,448963343,518352198,573271375,716227365,
	0,34,171,2115,16334,159651,1382259,12727570,113555791,29574624,258357071,605623228,361549414,928674293,295065969,684522478,
	0,55,341,5933,59925,795611,9167119,113555791,355115594,484061657,549328511,674425392,431913718,978012348,363063206,414679411,
	0,89,683,16717,221799,4005785,61643709,29574624,484061657,718817248,59031385,435203892,656660707,535833237,722768584,996059054,
	0,144,1365,47003,817280,20064827,411595537,258357071,549328511,59031385,789281595,298546930,255096739,647678030,196785642,770981649,
	0,233,2731,132291,3018301,100764343,758179825,605623228,674425392,435203892,298546930,245046738,624310766,911493467,712203752,78449372,
	0,377,5461,372157,11134189,505375405,448963343,361549414,431913718,656660707,255096739,624310766,681555006,234007277,697537938,825144798,
	0,610,10923,1047181,41096528,536323131,518352198,928674293,978012348,535833237,647678030,911493467,234007277,413451720,247090622,766966594,
	0,987,21845,2946251,151643937,724854929,573271375,295065969,363063206,722768584,196785642,712203752,697537938,247090622,571703274,855055410,
	0,1597,43691,8289731,559640289,851706016,716227365,684522478,414679411,996059054,770981649,78449372,825144798,766966594,855055410,7017421,
};
bool ok(int x,int b){
	int cnt=0;
	while(x>0){
		if(x & 1) ++cnt;
		x/=2;
	}
	return (cnt==b);
}
LL a_b_MOD_c(LL a,LL b,LL mod){
	LL ret = 1;
	a %= mod;
	while(b){
		if(b & 1) ret = ret * a % mod;
		a = a * a % mod;
		b >>= 1;
	}
	return ret;
}
map< pair
         
          
          
            ,int >,int> mp; LL p[20]; LL gao(int x,int y,int L,int b){ int C[20],R[20],cc=0,cr=0; memset(C,0,sizeof(C)); memset(R,0,sizeof(R)); int l=0,r=0; while(x>0){ ++r; if(x & 1){ if(r-l-1) C[r-l-1]++; l=r; } x/=2; } r=L+1; if(r-l-1) C[r-l-1]++; int tmp=0,rec=0,pp; for(int i=1;i<=15;++i){ for(int j=0;j 
           
             0){ ++r; if(y & 1){ if(r-l-1) R[r-l-1]++; l=r; } y/=2; } r=L+1; if(r-l-1) R[r-l-1]++; tmp=0,rec=0; for(int i=1;i<=15;++i){ for(int j=0;j 
            
              y) swap(x,y); tmp=mp[make_pair(make_pair(x,y),L)]; if(tmp) return tmp; LL ret=1; for(int i=0;i<=15;++i) for(int j=0;j<=15;++j){ if(C[i] && R[j] && tab[i][j]){ ret=ret*a_b_MOD_c((LL)tab[i][j],(LL)C[i]*R[j],(LL)MOD)%MOD; } } ret=ret*p[b]%MOD; mp[make_pair(make_pair(x,y),L)]=ret; return ret; } int tt[]={3,5,6,9,10,12}; int main(){ p[0]=1; for(int i=1;i<=15;++i){ p[i]=p[i-1]*i%MOD; } for(int i=1;i<=15;++i){ for(int j=0;j<=15;++j){ mp.clear(); if(j>i){ cout<<"0,"; continue; } cnt=0; for(int k=0;k<(1< 
              
             
            
           
         
        
        
      
      
     
     


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值