zoukankan      html  css  js  c++  java
  • [HNOI2012]排队

    题目描述

    某中学有 n 名男同学,m 名女同学和两名老师要排队参加体检。他们排成一条直线,并且任意两名女同学不能相邻,两名老师也不能相邻,那么一共有多少种排法呢?(注意:任意两个人都是不同的)

    输入输出格式

    输入格式:

    只有一行且为用空格隔开的两个非负整数 n 和 m,其含义如上所述。 对于 30%的数据 n<=100,m<=100 对于 100%的数据 n<=2000,m<=2000

    输出格式:

    输出文件 output.txt 仅包含一个非负整数,表示不同的排法个数。注意答案可能很大。

    输入输出样例

    输入样例#1:
    1  1
    输出样例#1:
    12
    考虑将老师和女生放到男生中间(注意这道题每个人不一样)
    男生排列方案:A(n,n)
    现在有n+1个间隔,要将2个老师放入:A(n+1,2)
    现在产生了n+3个间隔,将m个女生放入:A(n+3,m)

    但是我们忽略了一种方案
    我们算的是将老师分别放到男生中间,也就是说,隔开老师的必有一个男生
    实际上可以只放一个女生
    把2个老师和1个女生和为一块,放入男生中方案:n+1
    放剩下的女生:A(n+2,m-1)
    选出1个女生:C(m,1)
    老师排列方案:A(2,2)=2
    男生排列方案:A(n,n)

    所以ans=A(n,n)*A(n+1,2)*A(n+3,m)+(n+1)*A(n+2,m-1)*C(m,1)*A(n,n)*2
    因为不取模,所以必须要高精度
     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<algorithm>
     5 #include<cmath>
     6 using namespace std;
     7 int ans1[100001],ans2[100001],ans[100001],len1,len2,len;
     8 int n,m;
     9 void calc1(int x)
    10 {int i;
    11   for (i=1;i<=len1;i++)
    12     {
    13       ans1[i]*=x;
    14     }
    15   for (i=1;i<=len1;i++)
    16     if (ans1[i]>=10)
    17       {
    18     ans1[i+1]+=ans1[i]/10;
    19     ans1[i]%=10;
    20       }
    21   while (ans1[len1+1]) 
    22     {
    23       len1++;
    24       if (ans1[len1]>=10)
    25     {
    26       ans1[len1+1]+=ans1[len1]/10;
    27       ans1[len1]%=10;
    28     }
    29     }
    30 }
    31 void calc2(int x)
    32 {int i;
    33   for (i=1;i<=len2;i++)
    34     {
    35       ans2[i]*=x;
    36     }
    37   for (i=1;i<=len2;i++)
    38     if (ans2[i]>=10)
    39       {
    40     ans2[i+1]+=ans2[i]/10;
    41     ans2[i]%=10;
    42       }
    43   while (ans2[len2+1]) 
    44     {
    45       len2++;
    46       if (ans2[len2]>=10)
    47     {
    48       ans2[len2+1]+=ans2[len2]/10;
    49       ans2[len2]%=10;
    50     }
    51     }
    52 }
    53 void add()
    54 {int i;
    55   len=max(len1,len2);
    56   for (i=1;i<=len;i++)
    57     ans[i]=ans1[i]+ans2[i];
    58   for (i=1;i<=len;i++)
    59     if (ans[i]>=10)
    60       {
    61     ans[i+1]+=ans[i]/10;
    62     ans[i]%=10;
    63       }
    64   while (ans[len+1]) 
    65     {len++;
    66     if (ans[len]>=10)
    67     {
    68       ans[len+1]+=ans[len]/10;
    69       ans[len]%=10;
    70     }
    71     } 
    72 }
    73 int main()
    74 {int i;
    75   cin>>n>>m;
    76   ans1[1]=1;len1=1;
    77   for (i=1;i<=n;i++)
    78     calc1(i);
    79   calc1(n+1);calc1(n);
    80   for (i=n+3;i>=n+4-m;i--)
    81     calc1(i);
    82 
    83   ans2[1]=1;len2=1;
    84   calc2(n+1);
    85   for (i=n+2;i>=n+4-m;i--)
    86     calc2(i);
    87   calc2(m);
    88   for (i=1;i<=n;i++)
    89     calc2(i);
    90   calc2(2);
    91   add();
    92   for (i=len;i>=1;i--)
    93     printf("%d",ans[i]);
    94 }
  • 相关阅读:
    ObjectiveC初步研究 实现文件(Implementation File)
    SQL技巧(二) CTE(公用表达式)初步接触
    ObjectiveC编程基础
    Linux编程 使用C在mysql中插入数据
    办理户口
    修改kernel内核HZ频率没有效果问题
    如何从湖北省人才市场将户口迁移出来?
    查看 各种寄存器值的 内核模块 C语言
    SDRAM AND SRAM
    linux2.6.26内核中ARM中断实现详解(转)
  • 原文地址:https://www.cnblogs.com/Y-E-T-I/p/7636568.html
Copyright © 2011-2022 走看看