zoukankan      html  css  js  c++  java
  • 【u022】车的放置

    【问题描述】


    【题解】

    先考虑一个最简单的情况。如一个n*n的棋盘。然后要放k个车。

    我们可以先选出k行即C(n,k);

    然后在列上对这k个棋子进行一次全排列即A(n,k);

    比如k = 4;N=5

    选的行为1,2,3,4

    然后枚举的列1,2,3,4和4,3,2,1

    前者表示第一行放在1,第二行放在2,。。。第4行放在4.(列)

    后者表示第一行放在4,第二行放在3.。。。第4行放在1的位置.(列)

    这是进行全排列的原因。

    然后答案就是C(n,k)*A(n,k);

    然后把原题的图切成下面的样子


    然后在上面的小矩形内枚举放置i个棋子。

    方案就是C(b,i)*A(a,i);

    在下面。因为左边被占据了i列。所以下面可以用的只剩下a+c-i列。

    可以看成是一个长为a+c-i,宽为d的矩形。

    则在下面的方案为C(d,k-i)*A(a+c-i,k-i);

    然后对于枚举的i,如果可行。则答案递增C(b,i)*A(a,i)*C(d,k-i)*A(a+c-i,k-i)

    要记得取模。

    然后组合数可以用C[i][j] = c[i-1][j]+c[i-1][j-1]得到。

    然后因为


    所以要求排列数可以用组合数乘上一个k!

    一边取模就可以了。

    然后因为C(b,i)*A(a,i)*C(d,k-i)*A(a+c-i,k-i) 中出现了a+c-i。所以把组合数开到[2000][2000]

    不然会错!而且编译器不会告诉你数组越界了!

    还有一种分法。


    则对于枚举的i变成递增答案C(d,i)*A(c,i)+C(b+d-i,k-i)*A(a,k-i);

    【代码】--按照第一种分法做的。

    #include <cstdio>
    #include <stdlib.h>
    
    const int mo = 100003;
    long long A[2001][2001], C[2001][2001], N1[2001], ans = 0; //乘的时候可能会超过int类型所以用Longlong了。
    int a, b, c, d, k;
    
    void init()
    {
    	for (int i = 0; i <= 2000; i++) //获取组合数
    		C[i][0] = 1, C[i][i] = 1;
    	for (int i = 1; i <= 2000; i++) 
    		for (int j = 1; j <= i; j++)
    			C[i][j] = (C[i - 1][j] + C[i - 1][j - 1]) % mo;
    	N1[0] = 1;
    	for (int i = 1; i <= 2000; i++) //获取1到2000的阶乘,当然都是取模后的结果。
    		N1[i] = (N1[i - 1] * i) % mo;
    	for (int i = 0; i <= 2000; i++) //用相应的组合数来获取排列数。
    		for (int j = 0; j <= i; j++)
    			A[i][j] = (C[i][j] * N1[j]) % mo;
    }
    
    int min(int a, int b) //返回a和b中的较小值。
    {
    	return a>b ? b : a;
    }
    
    void input_data()
    {
    	scanf("%d%d%d%d%d", &a, &b, &c, &d, &k);//输入数据
    	int maxk = min(a, b); //这是在上面那个小矩形内能够放下的最大的车的数量
    	for (int i = 0; i <= maxk; i++) //枚举在那个小矩形内放几个车
    	{
    		if ((k - i) > d) continue;
    		if ((a + c - i)<(k - i)) continue; //如果下面的大矩形不能放下剩余的k-i个车则跳过
    		ans = (ans + ((((C[b][i] * A[a][i]) % mo)*((C[d][k - i] * A[a + c - i][k - i]) % mo)) % mo)) % mo;
    		//否则按照题解的思路递增答案。
    	}
    }
    
    void output_ans()
    {
    	printf("%I64d", ans);
    }
    
    int main()
    {
    	//freopen("F:\rush.txt","r",stdin);
    	//freopen("F:\rush_out.txt", "w", stdout);
    	//freopen("place.in","r",stdin);
    	//freopen("place.out","w",stdout);
    	init();
    	input_data();
    	output_ans();
    	//fclose(stdin);
    	//	fclose(stdout);
    	return 0;
    }


  • 相关阅读:
    SQL经典语句和要点整理
    XMLHTTPRequest状态status完整列表
    console和windows子系统
    QT的文件查找
    QT的编译原理
    AES加密算法
    多线程基础
    0210. Course Schedule II (M)
    ip段/数字,如192.168.0.1/24的意思是什么?
    Excel如何让日期单元格随着某个单元格的修改而自动更新
  • 原文地址:https://www.cnblogs.com/AWCXV/p/7632329.html
Copyright © 2011-2022 走看看