1. 程式人生 > 實用技巧 >NOIP 提高組 2016 組合數問題

NOIP 提高組 2016 組合數問題

肝了億天的程式碼(我太蒻了QWQ)

洛谷大大P2822(https://www.luogu.com.cn/problem/P2822

題目描述
組合數表示的是從n個物品中選出m個物品的方案數。舉個例子,從(
1,2,3)三個物品中選擇兩個物品可以有(1,2),(1,3),(2,3)這三種選擇方法。根據組合數的定義,我們可以給出計算組合數的一般公式:
組合數(n,m)= n!
m!(n-m)!特別地,定義0!=1。 小蔥想知道如果給定n,m和k對於所有的0≤i≤n,0≤j≤min(i,m)有多少對(i,j)滿足k|組合數(i,j)。

簡單來說,給定n,m,k,求出使k整除組合數(i,j)的i,j的對數。

程式實現分為三部分,預處理,讀入和判斷輸出。

核心思想是將k分解質因數(小於20即可),然後列舉i和j,利用字首和進行判斷。

額。。。

還是上程式碼吧。。。

(本人碼風 驚 奇 ,見諒 [ 抱拳 ] )

#include<bits/stdc++.h>
using namespace std;
int t,k,f[2001][10],F[2001][10],d[10],p[10],v[10]={0,2,3,5,7,11,13,17,19,0},g[2002][2002];//v陣列儲存判斷所需質數
void fi(int a){//fi函式用於預處理分解小於2000的數
    for(int i=1;i<=8;i++){
        
int r=a; while(r%v[i]==0){ f[a][i]++;//f陣列儲存1~2000每個數每個質因子的個數 r/=v[i]; } } return ; } void c(int x,int y){//c函式用於求出指定i和j的每個質因子的個數 for(int i=1;i<=8;i++){ p[i]=F[x][i]-F[y][i]-F[x-y][i];//p陣列儲存指定i和j的每個質因子個數,根據公式,n-m-(n-m)即為組合數質因子 } return ; }
int pd(){//pd函式用於判斷是否被k整除 for(int i=1;i<=8;i++){ if(d[i]>p[i]){ return 0; } } return 1; } int main(){ cin>>t>>k; for(int i=1;i<=2000;i++){//預處理 fi(i); } for(int i=1;i<=2000;i++){ for(int j=1;j<=8;j++){ F[i][j]=F[i-1][j]+f[i][j];//F陣列儲存1~2000各個字首和 } } for(int i=1;i<=8;i++){//對k進行分解 int r=k; while(r%v[i]==0){ d[i]++; r/=v[i]; } } int n,m; for(int i=0;i<=2000;i++){//預處理列舉i和j(不用最後重複列舉) for(int j=0;j<=min(i,2000);j++){ memset(p,0,sizeof(p)); c(i,j); if(j>=1){ g[i][j]=g[i][j-1]+pd();//g陣列儲存指定i和最大的j的符合數量 } } } while(t--){ cin>>n>>m; int h=0; for(int i=0;i<=n;i++){ h+=g[i][min(i,m)];//求和計算 } cout<<h<<endl; } return 0; }

懂?