• uva 12371 Guards (dp)


    题目链接:https://onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=3793

    首先发现按照规定的摆放方法一定会有圈,其中每个圈的相邻两行都有一对棋子位于同一列上

    (dp[i][j]) 表示 (i*i) 的棋盘上有 (j) 个圈的方案数,则转移的时候分增不增加圈数来讨论

    • 不增加圈数

    (i*i) 这个格子有没有守卫来讨论

    如果有,只需从前 (i-1) 行中选一行,将右侧的守卫移动到最后一列,再在最后一行的相应位置增加一个守卫即可,对应的转移方程为 (dp[i][j] += dp[i-1][j]*(i-1))

    如果没有,需要从前 (i-1) 列选择一列,将该列两个守卫移动到最后一列中同样的位置,然后在前 (i-1) 行选择一行,将左侧的守卫移动到之前选择的一列的最后一行,再加上最后一行剩余的守卫即可,对应的转移方程为 (dp[i][j] += dp[i-1][j] * (i-1) * (i-1))

    • 增加圈数

    由上面的讨论可知,还有一种情况是增加一个 (2*2) 的圈,方法是在最后一行选择两个位置作为下半部分,再在前 (i-1) 行选择一行作为上半部分,对应的转移方程为 (dp[i][j] += dp[i-2][j-1] * C_n^2 * (i-1))

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    
    const int maxn = 100010;
    const int maxk = 55;
    const int M = 1000000007;
    
    int T, n, k;
    int dp[maxn][maxk];
    
    int sqr(ll x){
    	x %= M;
    	return 1ll * x * x % M;
    }
    
    ll read(){ ll s = 0, f = 1; char ch = getchar(); while(ch < '0' || ch > '9'){ if(ch == '-') f = -1; ch = getchar(); } while(ch >= '0' && ch <= '9'){ s = s * 10 + ch - '0'; ch = getchar(); } return s * f; }
    
    int main(){
    	dp[2][1] = 1;
    	for(int i = 3 ; i <= 100000 ; ++i){
    		for(int j = 1 ; j <= 50 ; ++j){
    			dp[i][j] = 1ll * dp[i-1][j] * (i-1) % M * i % M;
    			dp[i][j] = (dp[i][j] + 1ll * dp[i-2][j-1] * (1ll * i * (i-1)/2) % M * (i-1) % M) % M;
    		}
    	}
    	
    	scanf("%d", &T);
    	for(int kase = 1 ; kase <= T ; ++kase){
    		scanf("%d%d", &n, &k);
    		printf("Case %d: %d
    ", kase, dp[n][k]);
    	}
    	return 0;
    }
    
  • 相关阅读:
    windows系统中ubuntu虚拟机安装及web项目到服务上(二)
    windows系统中ubuntu虚拟机安装及web项目到服务上(一)
    每个配置xml的含义作用
    第三天气接口使用总结
    js模式学习
    mac下php环境配置
    struts2
    MySQL常用命令
    JavaMail邮件开发
    文件上传与下载
  • 原文地址:https://www.cnblogs.com/tuchen/p/15113597.html
Copyright © 2020-2023  润新知