标签:targe 旋转 ++ string while ret target span sigma
https://vjudge.net/problem/UVA-861
题意:
在n*n棋盘上方k个互不攻击的象,求方案数
若两个象在同意对角线上,则会互相攻击
将棋盘黑白染色,则黑格不会攻击白格,白格不会攻击黑格
所以黑白格分开考虑
最终答案= Σ 黑格放i个*白格放k-i个
将所有黑格抽离出来,旋转45°
这样对角线方向就变成了水平方向和竖直方向
问题转化成了 每一行每一列至多放1个
在按每行格子数量从小到大排序
这样每行依次为 2个、2个、4个、4个、6个、6个、8个、8个……
或者每行一次为 1个、1个、3个、3个、5个、5个、7个、7个……
dp[i][j] 表示前i行放了j个的方案数
如果第i行不放,就是dp[i-1][j]
如果第i行放,有j-1列在前i-1行放过了,所以第i行有 该行格数-(j-1)个 位置可以放,就是 dp[i-1][j-1]*(sum-j+1)
用s[i]表示第i行有多少格子
dp[i][j]=dp[i-1][j]+dp[i-1][j-1]*(s[i]-j+1)
这样就求出只有黑格或者只有白格的情况,再合并即可
vjudge一直在pending,先把代码粘上吧。。。。。。
#include<cstdio> #include<cstring> using namespace std; #define N 9 typedef long long LL; int b[N],w[N]; LL f[N][N],g[N][N]; void solve(int n,int k,int s[N],LL dp[N][N]) { memset(dp,0,sizeof(dp)); for(int i=0;i<=n;++i) dp[i][0]=1; for(int i=1;i<=n;++i) for(int j=1;j<=k && j<=i;++j) dp[i][j]=dp[i-1][j]+dp[i-1][j-1]*(s[i]-j+1); } int main() { int n,k; LL ans; b[1]=2; for(int i=2;i<=8;++i) if(i&1) b[i]=b[i-1]+2; else b[i]=b[i-1]; w[1]=1; for(int i=2;i<=8;++i) if(i&1) w[i]=w[i-1]+2; else w[i]=w[i-1]; while(1) { scanf("%d%d",&n,&k); if(!n && !k) return 0; solve(n-1,k,b,f); solve(n,k,w,g); ans=0; for(int i=0;i<=k;++i) if(i<=n && k-i<=n) ans+=f[n-1][i]*g[n][k-i]; printf("%lld\n",ans); } }
标签:targe 旋转 ++ string while ret target span sigma
原文地址:https://www.cnblogs.com/TheRoadToTheGold/p/12244188.html