zoukankan      html  css  js  c++  java
  • [NOIP2016day2T1] 組合數問題(problem)

    题目描述

    组合数C(n,m)表示的是从n个物品中选出m个物品的方案数。举个例子,从(1,2,3) 三个物品中选择两个物品可以有(1,2),(1,3),(2,3)这三种选择方法。根据组合数的定 义,我们可以给出计算组合数的一般公式:

    C(n,m)=n!/m!(n-m)!

    其中n! = 1 × 2 × · · · × n

    小葱想知道如果给定n,m和k,对于所有的0 <= i <= n,0 <= j <= min(i,m)有多少对 (i,j)满足C(i,j)是k的倍数。

    输入输出格式

    输入格式:

    第一行有两个整数t,k,其中t代表该测试点总共有多少组测试数据,k的意义见 【问题描述】。

    接下来t行每行两个整数n,m,其中n,m的意义见【问题描述】。

    输出格式:

    t行,每行一个整数代表答案。

    输入输出样例

    输入样例#1:
    1 2
    3 3
    输出样例#1:
    1
    输入样例#2:
    2 5
    4 5
    6 7
    输出样例#2:
    0
    7

    说明

    【样例1说明】

    在所有可能的情况中,只有C(2,1)=2是2的倍数。

    【子任务】

    這個題,首先暴力思路是質因數分解。(70分)

     1 #include<cstdio>
     2 int t,k,n,m,ans,pd,a;
     3 int s[8]={2,3,5,7,11,13,17,19};
     4 int bz[8],bd[8];
     5 int main(){
     6     freopen("problem.in","r",stdin);
     7     freopen("problem.ans","w",stdout);
     8     scanf("%d%d",&t,&k);
     9     for(int i=0;i<8&&k>=s[i];i++) while(k%s[i]==0){k/=s[i];bz[i]++;}
    10     while(t--){
    11         ans=0;
    12         scanf("%d%d",&n,&m);
    13         for(int i=0;i<=n;i++)
    14         for(int j=0;j<=i&&j<=m;j++){
    15             pd=1;
    16             for(int k=j+1;k<=i;k++){
    17                 a=k;
    18                 for(int l=0;l<8&&a>=s[l];l++) while(a%s[l]==0){a/=s[l];bd[l]++;}
    19             }
    20             for(int k=1;k<=i-j;k++){
    21                 a=k;
    22                 for(int l=0;l<8&&a>=s[l];l++) while(a%s[l]==0){a/=s[l];bd[l]--;}
    23             }
    24             for(int k=0;k<8;k++){
    25                 if(bd[k]<bz[k]) pd=0;
    26                 bd[k]=0;
    27             }
    28             ans+=pd;
    29         }
    30         printf("%d
    ",ans);
    31     }
    32 }
    暴力

    然後,組合數有一個遞推公式,即C(i,j)=C(i-1,j)+C(i-1,j-1),也就是大名鼎鼎的楊輝三角。

     1 #include<cstdio>
     2 int t,k,n,m,ans;
     3 int c[2010][2010];
     4 int main(){
     5     freopen("problem.in","r",stdin);
     6     freopen("problem.ans","w",stdout);
     7     scanf("%d%d",&t,&k);
     8     c[1][0]=c[1][1]=1;
     9     for(int i=2;i<=2000;i++)
    10     for(int j=0;j<=i;j++){
    11         c[i][j]=c[i-1][j]+c[i-1][j-1];
    12         c[i][j]%=k;
    13     }
    14     while(t--){
    15         ans=0;
    16         scanf("%d%d",&n,&m);
    17         for(int i=1;i<=n;i++)
    18         for(int j=0;j<=i&&j<=m;j++)
    19         if(!c[i][j]) ++ans;
    20         printf("%d
    ",ans);
    21     }
    22     return 0;
    23 }
    90分

     而後提前處理一下,把查詢變成O(1)。

     1 #include<cstdio>
     2 int t,k,n,m,a;
     3 int c[2010][2010];
     4 int ans[2010][2010];
     5 int main(){
     6     freopen("problem.in","r",stdin);
     7     freopen("problem.ans","w",stdout);
     8     scanf("%d%d",&t,&k);
     9     c[1][0]=c[1][1]=1;
    10     for(int i=2;i<=2000;i++)
    11     for(int j=0;j<=i;j++){
    12         c[i][j]=c[i-1][j]+c[i-1][j-1];
    13         c[i][j]%=k;
    14     }
    15     for(int i=1;i<=2000;i++){
    16         a=0;
    17         for(int j=0;j<i;j++){
    18             if(!c[i][j]) ++a;
    19             ans[i][j]=ans[i-1][j]+a;
    20         }
    21         for(int j=i;j<=2000;j++) ans[i][j]=ans[i][i-1];
    22     }
    23     while(t--){
    24         scanf("%d%d",&n,&m);
    25         printf("%d
    ",ans[n][m]);
    26     }
    27     return 0;
    28 }

    NOIP第二水的題,而後。。。

  • 相关阅读:
    [恢]hdu 1412
    [恢]hdu 2212
    [恢]hdu 1407
    [恢]hdu 1228
    [恢]hdu 1337
    [恢]hdu 1014
    [恢]hdu 2200
    定居到博客园了!
    比较GridView,DataList,Repeator ,DetailsView,FormView
    随手记录修改某条记录时,不使用数据库控件而用datareader
  • 原文地址:https://www.cnblogs.com/J-william/p/6131018.html
Copyright © 2011-2022 走看看